跳至內容

在 ZFS 上安裝 Arch Linux

出自 Arch Linux 中文维基

這篇文章詳細描述了將 Arch Linux 安裝在 ZFS 文件系統上所需的步驟。

創建自定義 ISO

要在 ZFS 上安裝 Arch Linux,您需要使用帶有 ZFS 內核模塊安裝介質

請按照 archiso#安裝 的步驟操作。

接下來,依照 archiso#準備自定義配置文件 來準備一個自定義的配置文件(下文中以 archlive 為例),另請參閱 archiso#ArchZFS_實例

下一步,編輯軟體包列表 packages.x86_64 並在其中加入 linux-lts 內核與下列 ZFS 軟體包:

本文或本章節的事實準確性存在爭議。

原因: 為何需要 libunwind?如果有任何 ZFS 軟體包需要它,則它應該已經是相關軟體包的依賴項。(在 Talk:在 ZFS 上安裝 Arch Linux 中討論)


packages.x86_64
...
linux-lts
linux-lts-headers
libunwind
zfs-utils
zfs-dkms

請確保從列表中移除 linuxbroadcom-wl (後者會拉取 linux 包),並將 airootfs/etc/mkinitcpio.d/linux.preset 刪除。

您還需要編輯 pacman.conf 並在其中加入:

本文或本章節可能需要合併到非官方用戶倉庫#archzfs

附註: 重複關於 pacman.conf 的相關教程沒有意義,寫明指向非官方用戶倉庫#archzfs 的連結即可,否則用戶可能重複更改 Server 部分。(在 Talk:在 ZFS 上安裝 Arch Linux 中討論)
...
[archzfs]
SigLevel = TrustAll Optional
Server = https://github.com/archzfs/archzfs/releases/download/experimental

您還需要編輯引導加載器的配置文件,以將 vmlinuz-linuxinitramfs-linux.img 的條目分別改為 vmlinuz-linux-ltsinitramfs-linux-lts.img:

$ sed -i -E 's/(vmlinuz|initramfs)-linux/&-lts/g' archlive/efiboot/loader/entries/*.conf archlive/syslinux/*.cfg archlive/grub/*.cfg

接下來,開始鏡像的構建過程:

$ mkarchiso -v -r -w /tmp/archiso-tmp -o isobuild ~/archlive

現在,您的 archlive/isobuild 目錄下應該已經出現了archlinux-YYYY.MM.DD.x86_64.iso

請將該文件燒錄至您選擇使用的安裝介質。

注意:
  • 如果在系統更新後,zpool status -v 的輸出顯示您的存儲池需要升級以支持新的特性,您可能需要重新製作上述安裝介質。
  • 在實際安裝時,您應該使用 linux-ltslinux-lts-headers 來保證最大兼容性。
  • 您應從非官方的 archzfs 倉庫而非 AUR 獲取 zfs-utilszfs-dkms 的更新。如果您選擇使用 AUR 中的版本,則可能出現當前的主線或 zen 內核不被 ZFS 支持的情況,從而導致您的系統無法啟動。因此,在實際操作時,建議您使用 linux-lts 內核。

請確保先在虛擬機中測試您的 ISO。只需運行:

# modprobe zfs
# zpool status

如果命令執行失敗,則您的 ZFS 模塊並未成功構建,您需要重新嘗試。

警告:請勿分發您的自定義 ISO 鏡像,否則您將違反 GNU 通用公共許可證 (GPL) 與通用開發和發行許可證 (CDDL)。

分區

ZFS 支持 GUID 分區圖與主引導記錄分區表。要決定使用哪種分區圖,請參考分區#選擇_GPT_還是_MBR

提示:
  • 雖然您可以為舊設備創建基於主引導記錄的可引導 ZFS 根分區,但更建議您使用 GUID 分區圖。
  • 推薦您使用單獨的 /boot 分區以避免有關引導加載程序的問題,同時保證最好的兼容性。

ZFS 會管理自己的分區,所以只需創建一個最簡單的分區類型即可。創建 ZFS 文件系統的分區類型應為類型 bf00 ,或「 Solaris 根目錄分區」:

Part     Size   Type
----     ----   -------------------------
   1       1G   EFI system partition (ef00)
   2     XXXG   Solaris Root (bf00)

在 BIOS(或一台以 Legacy 模式啟動的)設備上使用 GUID 分區圖與 GRUB 啟動引導器的示例:

Part     Size   Type
----     ----   -------------------------
   1       2M   BIOS boot partition (ef02)
   2       1G   Linux Partition (8300)
   3     XXXG   Solaris Root (bf00)

您可以選擇創建獨立的 linux 交換分區或將 zvol 用作交換空間,後者詳見 ZFS#交換卷

如果您想要創建一個傳統的交換分區,詳見 分區#布局示例

若您創建了單獨的 boot 分區以及其他非 ZFS 分區,請將其格式化

設置 ZFS 文件系統

首先,確認 ZFS 內核模塊已經被加載,

# modprobe zfs

創建根存儲池

創建存儲池並設置好數據集的默認選項。存儲池上新創建的任何數據集都會保留這個存儲池創建時使用 -O 設定的選項。默認選項在在 ZFS 上安裝 Debian Buster # 第二步: 磁碟格式化中有詳細說明。

注意:物理扇區大小為512位元組的磁碟驅動器應使用 -o ashift=9 參數,而物理扇區大小為4096位元組的磁碟驅動器應使用 -o ashift=12 參數。要獲得每個 SCSI/SATA 磁碟驅動器的物理扇區大小,可以運行 lsblk -S -o NAME,PHY-SEC。如果想查看所有設備的物理扇區大小,可從命令中刪去 -S。若使用 NVMe 驅動器,使用 nvme id-ns /dev/nvmeXnY -H | grep "LBA Format" 來獲取正在使用的邏輯塊地址。大部分 NVMe 驅動器使用512位元組的邏輯塊大小,見 OpenZFS: NVMe low level formatting 以將其大小改為4096位元組。
警告:應始終注意現代的大部分設備的物理扇區大小為4096位元組,但有些設備會將自己的物理扇區大小報告為512位元組,尤其是固態驅動器(SSD)。即使在報告扇區大小為512位元組、實際物理扇區大小為4096位元組的設備上選擇 ashift=9一定會導致嚴重的性能下降。在物理扇區大小為512位元組的設備上選擇 ashift=12 不會導致性能下降,但可能使磁碟實際可用的空間減少。如果您不確定的話,對於現代設備,應使用 ashift=12,或者您可以搜索您設備對應的正確值。對於有關的討論,參見 OpenZFS issue #967 ;對設置較高的 ashift 值可能出現的問題,見 OpenZFS issue #2497
警告: 接下來創建存儲池時,如果使用例如 /dev/nvme0n1p2 的一般設備名而不是 /dev/disk/by-id/<device number> 來創建存儲池,則有可能會使存儲池的導入出現問題。若要在下一部分開始前知曉您設備的正確 by-id 名稱,請運行:

ls -lh /dev/disk/by-id/

並記錄您將要使用的正確 by-id 名稱,而非標準設備名,如:

lrwxrwxrwx 1 root root 9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0JKRR -> ../../sdc

使用壓縮與 TRIM

# zpool create -f -o ashift=12         \
             -o autotrim=on            \
             -O acltype=posixacl       \
             -O relatime=on            \
             -O xattr=sa               \
             -O dnodesize=auto       \
             -O normalization=formD    \
             -O mountpoint=none        \
             -O canmount=off           \
             -O devices=off            \
             -R /mnt                   \
             -O compression=lz4        \
             zroot /dev/disk/by-id/id-to-partition-partx

使用壓縮, TRIM 與原生加密

以下命令創建的存儲池會在所有數據集上默認啟用壓縮與原生加密:

# zpool create -f -o ashift=12         \
             -o autotrim=on            \
             -O acltype=posixacl       \
             -O relatime=on            \
             -O xattr=sa               \
             -O dnodesize=auto       \
             -O normalization=formD    \
             -O mountpoint=none        \
             -O canmount=off           \
             -O devices=off            \
             -R /mnt                   \
             -O compression=lz4        \
             -O encryption=aes-256-gcm \
             -O keyformat=passphrase   \
             -O keylocation=prompt     \
             zroot /dev/disk/by-id/id-to-partition-partx
注意:

前述所有選項對 GNU/Linux 系統都有意義,而且它們中的大部分在根文件系統上必須被使用,尤其是 canmountmountpoint,這點與通常的存儲設備設置方式不同。xattr, dnodesizenormalization 為可選項。

加密與壓縮為可選項,但本教程推薦您啟用壓縮。為了在數據無損壓縮存儲的情況下避免性能損失,建議使用 lz4 算法。較為均衡的 zstd 算法是默認壓縮選項。

您可以在手冊頁面 zfsprops(7)找到關於這些選項的詳細解釋。

-O 之後的參數將控制 ZFS 的行為。 您可以在 zfsprops(7) 手冊頁面中找到關於這些參數的詳細解釋。

警告:由於在不使用 spl hostid 與 zpool.cache 文件的情況下導入 ZFS 存儲池存在較多問題,且可能會導致存儲池損壞,本教程不使用 canmount=on 選項。如果您未設置 spl hostid 並使用 zfs-zed 加載您的存儲池,您在跨系統使用存儲池的情況下將面臨存儲池損壞的風險。
警告:
  • 使用 ZFS 時應始終使用設備的 id 名稱,否則導入存儲池時會發生錯誤。
  • 除使用 by-id 名稱外,也可以考慮使用 by-partuuidby-uuid 名稱,因為即使一個內置磁碟驅動器被移入USB移動硬碟盒,這些名稱的值也不會發生改變,反之亦然(這僅當 ZFS 在磁碟上的某個分區中才有效,若 ZFS 占據整個磁碟則無效)。

創建您的數據集

ZFS 使用數據集的概念來管理您的存儲設備,而非使用傳統的磁碟分區。與磁碟分區不同,數據集沒有固定的大小,每個數據集也可以有各自不同的屬性,例如壓縮。普通的 ZFS 數據集由 ZFS 自動掛載,而傳統類型的數據集則需由 fstab 或 使用 mount 命令掛載。

ZFS 最實用的功能之一便是啟動環境。啟動環境使您可以創建系統的可引導快照,您也可以通過簡單地重啟到某啟動環境來將整個系統回滾到那個快照。這使得系統更新變得更加安全,對軟體開發與測試來講也十分有用。要使用如 beadm, zectlAUR (用於 systemd-boot), or zedenvAUR (用於 GRUB) 等的啟動環境管理器來管理啟動環境,您的數據集必須有正確的配置。其關鍵是將您存放數據的目錄 (如 /home) 與系統數據分別放在相互獨立的不同數據集中,且不要在存儲池根目錄中存放數據,因為放在存儲池根目錄的數據以後將不能被移動。

您總是至少應該為您的根目錄創建一個數據集,且多數情況下您也會想要把 /home 存放在一個單獨的數據集中。您也可以自行選擇是否要無視啟動環境而始終保留完整的日誌文件。如果您使用的某些軟體會在 /home 之外存放數據 (如資料庫伺服器),您應整理數據集的結構,使得這些軟體的數據目錄與根目錄數據集分離開來。

以下的示例命令會創建一個只分根目錄數據集與 /home 數據集的最基本可用於啟動環境使用的配置。數據集使用其所在的存儲池在創建時設定的默認選項。

# zfs create -o mountpoint=none zroot/data
# zfs create -o mountpoint=none zroot/ROOT
# zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/default
# zfs create -o mountpoint=/home zroot/data/home

創建根目錄數據集時您也可以不將掛載點指定為 / ,畢竟無論如何 GRUB 啟動引導器會將其掛載至 / 。這也使得您可以通過克隆舊版數據集並將其放入 GRUB 啟動菜單來直接從舊版的根目錄啟動。這種情況下,您可以使用以下命令來創建您的根目錄數據集:

# zfs create -o mountpoint=/roots/default zroot/ROOT/default

您可以將 /root 存儲在您的 zroot/data/home 數據集中。

# zfs create -o mountpoint=/root zroot/data/home/root

系統數據集

為系統目錄創建數據集時,請使用canmount=off選項。

示例請參見 在 ZFS 上安裝 Debian Buster # 第三步:安裝系統

注意:若要將如 zroot/var/log 的數據集掛載至 /var/log,應考慮使用 zfs-mount-generator 而非 zfs-mount.service。這會修復文件系統掛載順序,在 這裡 有詳細介紹。
# zfs create -o mountpoint=/var -o canmount=off                 zroot/var
# zfs create                                                    zroot/var/log
# zfs create -o mountpoint=/var/log/journal -o acltype=posixacl zroot/var/log/journal
# zfs create -o mountpoint=/var/lib -o canmount=off             zroot/var/lib
# zfs create                                                    zroot/var/lib/libvirt
# zfs create                                                    zroot/var/lib/docker
注意:systemd-journald 需要您為 /var/log/journal/ 啟用 POSIX 訪問控制列表,即為該目錄所在的數據集設置 acltype=posix,否則 systemd-journald.service 將無法啟動。詳見 systemd#systemd-tmpfiles-setup.service在系統啟動時失敗

導出並導入您的存儲池

要驗證您的設置,將您所有的 ZFS 存儲池先導出後再重新導入。

警告:不要跳過這一步,否則您再導入存儲池時必須使用 -f 參數。這會使導入的存儲池卸載。
注意:如果您使用交換分區的話,這一步可能會失敗。您需要先使用 swapoff 命令將其關閉。
# zpool export zroot
# zpool import -d /dev/disk/by-id -R /mnt zroot -N
注意:-d 並不是設備的實際 ID,而是包含著符號連結的 /dev/by-id 目錄。

如果這個命令執行失敗並且您被要求使用數字 ID 來導入某個存儲池,運行 zpool import 來找到您存儲池的 ID,然後使用類似下方的命令導入存儲池:

# zpool import 9876543212345678910 -R /mnt zroot

如果您啟用了原生加密選項,請加載 ZFS 密鑰。

# zfs load-key zroot

由於根目錄數據集使用 canmount=noauto 參數,您需要先將其手動掛載,然後再掛載其他數據集。

# zfs mount zroot/ROOT/default
# zfs mount -a

現在,您的 ZFS 文件系統已準備就緒。

配置根目錄文件系統

如果您使用了傳統類型的數據集,則您需要將其寫入 /etc/fstab

為根目錄所在的子文件系統設置 bootfs(啟動文件系統)屬性,以便引導加載程序找到作業系統。

# zpool set bootfs=zroot/ROOT/default zroot

如果您還沒有 /etc/zfs/zpool.cache,請手動創建:

# zpool set cachefile=/etc/zfs/zpool.cache zroot

切記要將 zpool.cache 文件放入您的新系統中。稍後 ZFS 守護進程啟動時需要這個文件。

# mkdir -p /mnt/etc/zfs
# cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache

安裝並配置 Arch Linux

按照安裝指南安裝系統。若有涉及 ZFSonLinux 所需的特殊操作,將會在此列出。

  • 首先使用 mount 命令掛載所有的傳統類型數據集以及非 ZFS 的引導或系統分區。
  • 安裝基本系統。
注意:您可能想要在 pacstrap 操作時使用 linux-lts 作為您的內核。同時請確保使用 pacstrap 安裝 libunwind 從而為 zfs-utilsAUR 解析依賴項目。
  • 安裝指南#生成 fstab 文件中所描述的方式對 ZFS 來說並非必要。通常 ZFS 會自行掛載自己的分區,所以除非用戶為系統目錄使用了傳統類型數據集,fstab 文件中不需要任何有關 ZFS 的部分。 要為文件系統生成 fstab,運行:
# genfstab -U -p /mnt >> /mnt/etc/fstab
# arch-chroot /mnt
  • 編輯 /etc/fstab
注意:
  • 如果您選擇為系統目錄創建傳統類型數據集,則請在 fstab 中保留這些數據集。
  • 將除交換空間與 EFI 系統分區以外的所有非傳統類型數據集注釋掉。傳統做法是,可以使用較簡單的 /dev/zvol/zroot/swap 來取代交換空間的 UUID。
注意:出於簡潔性以及兼容性考慮,本指南建議您使用 zfs-dkmsAURlinux-lts
  • 創建初始 ramdisk 前,請先編輯 /etc/mkinitcpio.conf,並將 zfs 加至 MODULES:
MODULES=(zfs)

接下來在 HOOKS 中將 zfs 加至 filesystems 前,並將 systemd 切換為 udev。您的 HOOKS 一行看起來應類似如下示例:

HOOKS=(base udev ... block zfs filesystems)
警告:
  • 默認情況下,根文件系統為 ZFS 的情況下,不支持在 initramfs 中使用 systemd。使用 systemd 會導致 root 文件系統無法掛載,從而導致系統無法啟動。要解決這個問題,請將 mkinitcpio 使用的所有 systemd HOOK 更換為 mkinitcpio#常用鉤子中描述的基於 Busybox 的 hook。如果您仍然想要在 initramfs 中使用 systemd,請閱讀下文中關於 mkinitcpio-sd-zfsAUR 的信息。
注意:
  • zfs-utilsAUR 提供了一個開箱即用且適用於基於 systemd 的 initramfs 的 dracut hook。
  • zfs-utilsAUR 提供的 mkinitcpio 的 ZFS hook 僅兼容基於 busybox 的 initramfs 鏡像。
  • 對於使用了 ZFS 加密的用戶,建議您將 keyboard 移至 autodetect 前,以防止在輸入密碼時出現問題。
  • mkinitcpio-sd-zfsAUR 提供了與 systemd 兼容的 mkinitcpio initramfs 的 ZFS hook。請注意,"sd-zfs" hook 未經過完整測試,並且可能不兼容啟用了加密的文件系統。
  • 將 ZFS 添加至您的內核參數。

現在,請設置您的 引導加載程序。要使得 ZFS 可以啟動,您還需要以下的內核參數

root=ZFS=zroot/ROOT/default rw

設置 hostid

為了使您的系統能夠順利啟動,您還需要設置 hostid。

注意:
  • 本章節的內容假設您仍處在 arch-chroot 環境中。
  • 雖然 zpool.cache 正待廢棄,但zfs-utils 仍需要 zpool.cache 來獲得可以啟動的系統,故現在這仍是取得可啟動的系統的默認以及建議方式。[詳見: https://github.com/openzfs/zfs/issues/1035]

對每個您想自動掛載的存儲池運行以下命令:

# zpool set cachefile=/etc/zfs/zpool.cache pool

當根目錄文件系統為 ZFS 時,本機的 hostid 在掛載時將不可見。解決方案有兩種。您可以在引導加載程序中將您的 spl hostid 寫入 內核參數中,例如 spl.spl_hostid=0x00bab10c。要確定您的 hostid,請運行 hostid

另一種,同時也是推薦的解決方案,是保證 /etc/hostid 中寫入了 hostid,並重新生成 initramfs 以將其拷貝至 initramfs 鏡像內。要安全地寫入 hostid 文件,請使用 zgenhostid

要使用 libc 生成的 hostid(建議的操作):

# zgenhostid $(hostid)

要使用自定義的 hostid,運行以下命令(注意,hostid 必須是8個字符的十六進制數):

# zgenhostid deadbeef

完成後請勿忘記重新生成 initramfs

配置 ZFS 掛載 (適用於 systemd)

注意:

這一章節僅適用於 systemd,即 Arch Linux 默認使用的 init 系統。

要自動掛載存儲池,您需要啟用 zfs.target

啟用 zfs.target

要在系統啟動時自動掛載 ZFS 存儲池,您需要啟用 zfs-import-cache.servicezfs-mount.servicezfs-import.target

配置 ZFS 掛載 (適用於 OpenRC)

警告:

本章節適用於 OpenRC init 與服務管理系統的用戶。OpenRC 僅在 AUR 可用,Arch Linux 對其沒有官方支持。根據 OpenRC 頁面,當向他人求助時,您應聲明自己在使用 OpenRC。

注意:

雖然 Arch Linux 的默認 init 系統是 systemd,本章節仍出於文檔完整性的目的提供。

您需要將 zfs-importzfs-mount init 腳本添加至 boot runlevel。

# rc-update add zfs-import boot
# rc-update add zfs-mount boot
注意:

如果您啟用了 ZFS 加密並且希望在啟動時解鎖您的 ZFS 分區,還應將 zfs-load-key 添加至 boot runlevel。

# rc-update add zfs-load-key boot

卸載文件系統並重新啟動

我們離成功不遠了!如果您使用傳統類型的啟動引導分區,先運行:

# umount /mnt/boot 

如果未使用傳統的單獨引導分區,直接運行:

# zfs umount -a
# zfs umount zroot/ROOT/default
# zpool export zroot

現在,重新啟動系統。

警告:如果您沒有正確將存儲池導出,重新啟動後 ZFS 將拒絕在 ramdisk 環境中導入存儲池,從而使您卡在 busybox 終端界面。

從 USB 存儲設備加載密鑰

可以將密鑰存儲在 USB 存儲設備上並在啟動時加載:

在 USB 存儲介質的初始字節處存儲密鑰:

# dd if=your_password_file (您的密钥文件) bs=32 count=1 of=/dev/disk/by-id/usb_stick (USB 存储设备)

要創建 ZFS 分區,您可以使用上文所述的輸入密鑰的方式,或直接使用 dd 命令配合管道寫入 USB 存儲設備中存儲的密鑰:

# dd if=/dev/disk/by-id/usb_stick bs=32 count=1 | zfs create -o encryption=on -o keyformat=passphrase zroot/ROOT

下一步就要更改 zfs hook。zfs 默認會詢問密鑰。您需要將獲取密鑰的方式改為通過從您存放著密鑰的 USB 設備中 dd 來獲取。要達成這個目的,將 /usr/lib/initcpio/hooks/zfs 中的以下行:

# ! eval zfs load-key "${encryptionroot}"; do

改為:

# ! eval dd if=/dev/disk/by-id/usb_stick bs=32 count=1 | zfs load-key "${encryptionroot}"; do

您剛剛更改了您的 zfs hook,所以不要忘記重新生成 initramfs。現在 zfs 應該能在啟動時從您的 USB 設備中加載密鑰。

故障排除

系統因 "無法導入 zroot:存儲池不存在(cannot import zroot: no such pool available)" 而無法啟動

您可以嘗試以下步驟,看看是否有幫助。

  • 使用 archzfs 倉庫中提供的內核模塊,不要使用 dkms 版本。您可以在成功啟動後再改為使用 dkms 變種。
  • 移除 /etc/zfs/zpool.cache 並運行:
    # zpool set cachefile=none zroot
  • 移除 /etc/hostid
  • 重新生成 initramfs

zpool 因為忙碌而拒絕導出

Arch-chroot 會在系統裡掛在特定的內核空間文件系統。如果沒有卸載這些文件系統,存儲池可能會拒絕導出。此時,請重新掛載 ZFS 分區,並運行 findmnt -R /mnt

然後運行對於每個仍然掛載的文件系統,運行 umount -f /path/to/partition

之後您應當能夠正常導出您的存儲池。

另請參閱