在 ZFS 上安裝 Arch Linux
這篇文章詳細描述了將 Arch Linux 安裝在 ZFS 文件系統上所需的步驟。
由於 ZFS 不是 Linux 的原生文件系統(例如:不包含在主線內核之內)且 Arch Linux 是一個滾動更新發行版,總有些時候外部倉庫內的對應一定內核版本的內核模塊軟件包版本會稍落後於 Arch 倉庫中的版本,這有時會導致 ZFS 模塊(或其 dkms 變種包)在最新版本的內核上無法編譯。如果您想要一直使用最新版本的內核的話,將 Arch 安裝在 ZFS 上可能並不是很理想。
可能的解決方案見 ZFS#安裝。
安裝[編輯 | 編輯原始碼]
要在 ZFS 上安裝 Arch Linux,您需要使用帶有 ZFS 內核模塊的安裝介質。您可以選擇在官方 ISO 中添加相應內核模塊或創建一個自定義的安裝鏡像。
在 archiso 安裝介質上獲取 ZFS 模塊[編輯 | 編輯原始碼]
有一個腳本可以簡單地在 archiso 安裝介質上安裝並啟用 ZFS 模塊。它應該適用於任何版本的 archiso 安裝介質。
在自定義的 archiso 安裝介質中啟用 ZFS 模塊[編輯 | 編輯原始碼]
要構建一個自定義的 archiso 安裝介質,請參考 ZFS#Create an Archiso image with ZFS support。
對目標磁盤驅動器進行分區[編輯 | 編輯原始碼]
ZFS 支持 GUID 分區圖與主啟動記錄分區表。要決定使用哪種分區圖類型,請參考分區#選擇 GPT 還是 MBR。
ZFS 會管理自己的分區,所以只需創建一個最簡單的分區類型即可。創建 ZFS 文件系統的分區類型應為類型 bf00
,或「 Solaris 根目錄分區」。
分區類型[編輯 | 編輯原始碼]
這是一個可以用於在 BIOS/MBR 的 ZFS 設備上使用 GRUB 啟動引導器部署安裝的基本分區類型示例:
Part Size Type ---- ---- ------------------------- 1 XXXG Solaris Root (bf00)
在 BIOS(或一台以 Legacy 模式啟動的)設備上使用 GUID 分區圖與 GRUB 啟動引導器的示例:
Part Size Type ---- ---- ------------------------- 1 2M BIOS boot partition (ef02) 2 XXXG Solaris Root (bf00)
要在使用 BIOS 啟動模式並使用 GUID 分區圖或主啟動記錄的計算機上使用 Syslinux 與 zfsbootmenuAUR :
Part Size Type ---- ---- ------------------------- 1 512M XBOOTLDR partition (ea00) 2 XXXG Solaris Root (bf00)
這是另一個示例,這次使用的是 GUID 分區圖與 UEFI 啟動引導器(如 rEFInd ):
Part Size Type ---- ---- ------------------------- 1 1G EFI System Partition (ef00) 2 XXXG Solaris Root (bf00)
ZFS 不支持使用交換文件。如果您需要一個交換分區,參考 ZFS#交換卷來創建一個用於交換空間的 ZVOL。
示例 parted 命令[編輯 | 編輯原始碼]
這是適用於上述第二種使用 GUID 分區圖和 BIOS/Legacy 啟動情況的一些示例命令,其中為 GRUB 創建了一個(稍大於)1MB 的 BIOS 啟動分區:
# parted /dev/sdx
(parted)mklabel gpt (parted)mkpart non-fs 0% 2 (parted)mkpart primary 2 100% (parted)set 1 bios_grub on (parted)set 2 boot on (parted)quit
您也可以把上述命令變為如下的單行命令:
# parted --script /dev/sdx mklabel gpt mkpart non-fs 0% 2 mkpart primary 2 100% set 1 bios_grub on set 2 boot on
如果您需要創建一個 EFI 系統分區,那就應將其標記為啟動分區而非根分區。
格式化目標磁盤驅動器[編輯 | 編輯原始碼]
如果您已為啟動引導分區以及非 ZFS 文件系統創建了合適分區,那麼將其格式化。不要對剛創建的 Solaris 根分區以及您的 BIOS 啟動分區做任何操作。Solaris 根分區將由 ZFS 管理,而 BIOS 啟動分區則會由您的啟動引導器管理。
設置 ZFS 文件系統[編輯 | 編輯原始碼]
首先,確認 ZFS 內核模塊已經被加載,
# modprobe zfs
創建根存儲池[編輯 | 編輯原始碼]
創建存儲池並設置好數據集的默認選項。存儲池上新創建的任何數據集都會保留這個存儲池創建時使用 -O
設定的選項。默認選項在在 ZFS 上安裝 Debian Buster. 第二步: 磁盤格式化中有詳細說明。
-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位元組。ashift=9
也一定會導致嚴重的性能下降。在物理扇區大小為512位元組的設備上選擇 ashift=12
不會導致性能下降,但可能使磁盤可用容量減少。如果您不確定的話,對於現代設備,應使用 ashift=12
,或者您可以搜索您設備對應的正確值。對於有關的討論,參見 OpenZFS issue #967 ;對設置較高的 ashift 值可能出現的問題,見 OpenZFS issue #2497 。
# zpool create -f -o ashift=12 \ -O acltype=posixacl \ -O relatime=on \ -O xattr=sa \ -O dnodesize=legacy \ -O normalization=formD \ -O mountpoint=none \ -O canmount=off \ -O devices=off \ -R /mnt \ zroot /dev/disk/by-id/id-to-partition-partx
壓縮與原生加密[編輯 | 編輯原始碼]
以下命令創建的存儲池會在所有數據集上默認啟用壓縮與原生加密:
# zpool create -f -o ashift=12 \ -O acltype=posixacl \ -O relatime=on \ -O xattr=sa \ -O dnodesize=legacy \ -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
- 使用 ZFS 時應始終使用設備的 by-id 名稱,否則導入存儲池時會發生錯誤。
- 除使用 by-id 名稱外,也可以考慮使用 by-partuuid 或 by-uuid名稱,因為即使一個內置磁驅動器被移入USB移動硬盤盒,這些名稱的值也不會發生改變,反之亦然。(這僅當 ZFS 在磁盤上的某個分區中才有效,若 ZFS 佔據整個磁盤則無效)
- GRUB 啟動引導器用戶應注意的是 zpool-create 命令一般會默認啟用所有功能,而其中某些是 GRUB 啟動引導器不支持的功能。見: ZFS#GRUB-compatible pool creation 來創建與 GRUB 兼容的存儲池。
創建您的數據集[編輯 | 編輯原始碼]
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=noauto
|
|
/var/log/journal
|
acltype=posixacl
|
systemd#systemd-tmpfiles-setup.service在系統啟動時失敗 |
系統數據集[編輯 | 編輯原始碼]
為系統目錄創建數據集時,使用canmount=off
選項。
示例請參見 Debian-Buster-Root-on-ZFS#step-3-system-installation。
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/lib -o canmount=off zroot/var/lib # zfs create zroot/var/lib/libvirt # zfs create zroot/var/lib/docker
導出並導入您的存儲池[編輯 | 編輯原始碼]
要驗證您的設置,將您所有的 ZFS 存儲池先導出後再重新導入。
-f
參數。這會使導入的存儲池卸載。# 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 (您的设备的 ID) -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 的引導或系統分區。
- 安裝基本系統。
- 安裝指南#生成 fstab 文件中所描述的方式對 ZFS 來說絕非必要。通常 ZFS 會自行掛載自己的分區,所以除非用戶使用了傳統型數據集,
fstab
文件中不需要任何有關 ZFS 的部分。 要為文件系統生成fstab
,運行:
# genfstab -U -p /mnt >> /mnt/etc/fstab
- 依照安裝指南#chroot 到新安裝的系統中的方法將根目錄切換至新安裝的系統內。
# arch-chroot /mnt
- 編輯
/etc/fstab
:
- 如果您選擇為系統目錄創建傳統數據集,將其在
fstab
中保留。 - 將除交換空間與 EFI 系統分區以外的所有非傳統型數據集註釋掉。可以使用較簡單的
/dev/zvol/zroot/swap
來取代交換空間的 UUID。
- 在更新 ramdisk 並啟用 ZFS 支持前,您需要在
/etc/pacman.conf
中加入 Arch ZFS 倉庫,將其簽名並在 arch-chroot 環境下安裝 zfs-linuxAUR (如果您使用 LTS 長期支持版內核則安裝 zfs-linux-ltsAUR )。
- 創建初始 ramdisk 前,先編輯
/etc/mkinitcpio.conf
,並將zfs
加至MODULES
:
MODULES=(zfs)
接下來在 HOOKS
中將 zfs
加至 filesystems 前。同時也應把 keyboard
hook 移動至 zfs
前,這樣如果出現問題,您仍可在終端中輸入。若您不使用 Ext3 或 Ext4,您也可以移除 fsck。您的 HOOKS
一行看起來應類似如下示例:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block zfs filesystems)
- 若在 initrd 中使用 systemd hook,您應安裝 mkinitcpio-sd-zfsAUR 並將
sd-zfs
hook 而非zfs
hook 放至systemd
hook 後面。應注意的是此 hook 和默認的zfs
hook 相比使用了不同的內核參數,可在其項目主頁找到更多信息。
sd-zfs
暫不支持原生加密,見 dasJ/sd-zfs/issues/4。- 如果您的
/usr
存放在單獨的數據集上,並按照下面的指示進行了操作,您需要確認您的zfs
hook 後啟用了usr
hook ,否則您的系統將無法啟動。 - 當您生成 initramfs 時,
zpool.cache
文件會被複製到 initrd 中。如果您之前還未生成或需要重新生成zpool.cache
,記得在完成後重新生成 initramfs。 - 您也能使用
legacy
掛載點來讓 fstab 掛載它。
安裝並配置啟動引導加載器[編輯 | 編輯原始碼]
原則上講,只要內核與 initrd 在一個非 ZFS 分區上,那麼啟動引導器的配置就與平時沒有什麼差別。只要內核有 ZFS 模塊、生成 initrd 時正確地使用了 zfs
hook 且內核的命令行裡添加了 zfs
參數,系統就可以啟動。比如,大部分情況下, zfs=zroot/ROOT/default rw
就足夠了。如果您的根目錄文件系統參數是按照本篇內容設定好的,您甚至也可以只用 zfs=zroot rw
。您用不到 root
參數,因為 ZFS 會掛載根目錄。至於如何設定內核參數,詳見您所使用的啟動引導加載器的幫助文檔。
但是,如果您需要從 ZFS 上加載內核映像與/或 initrd,您就需要使用一個可以讀取 ZFS 的啟動引導器,並將其正確配置。
考慮到以上情況,配置您啟動引導加載器的過程應該還算直接。下面有一些例子,不過也不要被其所局限。
使用 EFISTUB[編輯 | 編輯原始碼]
如果您使用 EFISTUB 啟動引導器,您可以手動向您的 UEFI 啟動菜單中加入一個條目:
# efibootmgr --create --disk your_esp_disk --part your_esp_partition_number --label "Arch Linux (ZFS)" --loader /vmlinuz-linux --unicode 'zfs=zroot/ROOT/default rw initrd=\initramfs-linux.img'
使用統一內核映像 (Unified Kernel Image, UKI)[編輯 | 編輯原始碼]
使用統一內核映像 (UKI) 就會比較直接。您只需要確保您在 /etc/cmdline.d
中的某個地方加入了 zfs 參數即可。除了配置 mkinitcpio 模塊和 hook 的過程需要依照本文來做,其他部分與使用一個普通統一內核映像沒有區別。例如:
/etc/cmdline.d/root.conf
zfs=zroot/ROOT/default rw
設置 zfs=zroot
大概率就夠用了(未經過測試),畢竟 ZFS 應該可以自動掛載根目錄。只要記得每次作出更改時重新運行一遍 mkinitcpio 即可。
使用 GRUB[編輯 | 編輯原始碼]
如果您使用 GRUB 啟動引導器,您可以將您的 /boot 目錄保存在 ZFS 存儲池上。請詳細閱讀 Debian-Buster-Root-on-ZFS#step-3-system-installation。
您可以在 GRUB#BIOS 系統或 GRUB#UEFI 系統找到安裝 GRUB 的方法。GRUB 的手冊也提供了手動配置該軟件的詳細方法。您也可以閱讀 GRUB 和 GRUB/方法與技巧作為補充。
BUG: 無法檢測根存儲池[編輯 | 編輯原始碼]
一個已知的 BUG 會導致 grub-mkconfig 無法檢測根存儲池並將其正確寫入 /boot/grub/grub.cfg
中。這個 BUG 仍未修復,但有兩種解決方案:
- 解決方案 A :編輯
/etc/grub.d/10_linux
中檢測 rpool 的代碼。將
rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
- 替換為
rpool=`zdb -l ${GRUB_DEVICE} | grep " name:" | cut -d\' -f2`
- 這樣 grub-mkconfig 應該就能夠檢測到正確的存儲池名並將正確路徑寫入
/boot/grub/grub.cfg
。
- 解決方案 B :如果上述方法仍不起作用,您可以將正確路徑硬編碼至
/etc/grub.d/10_linux
內。將
linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} rw ${args}
- 替換為
linux ${rel_dirname}/${basename} root=ZFS=zroot/ROOT/default rw ${args}
錯誤:無法獲取 …… 的規範路徑(error: failed to get canonical path of)[編輯 | 編輯原始碼]
grub-mkconfig 無法正確地為 ZFS 上的系統生成相應條目。
# grub-mkconfig -o /boot/grub/grub.cfg
/usr/bin/grub-probe: error: failed to get canonical path of `/dev/bus-Your_Disk_ID-part#' grub-install: error: failed to get canonical path of `/dev/bus-Your_Disk_ID-part#'
要解決這個問題,您必須設置 ZPOOL_VDEV_NAME_PATH=1
環境變量。例如:
# ZPOOL_VDEV_NAME_PATH=1 grub-mkconfig -o /boot/grub/grub.cfg
錯誤:未知的文件系統(error: unknown filesystem)[編輯 | 編輯原始碼]
GRUB 的命令行工具,如 grub-probe 、 grub-install 等在無法檢測文件系統時可能會因 unknown filesystem
錯誤而執行失敗。這可能是因為使用了 GRUB 不支持的文件系統,或使用了 GRUB 不支持的 ZFS 參數(見 ZFS#GRUB-compatible pool creation 來為啟動所用的 ZFS 存儲池設定合適的參數)。
要排除這個故障,首先應找出 GRUB 無法辨認的是哪個文件系統(可以在您的懷疑對象上運行 grub-probe,例如 grub-probe /
或 grub-probe /boot
)。下面是一個示例:
# grub-probe /boot zfs # grub-probe / grub-probe: error: unknown filesystem.
找到出問題的文件系統後,運行 grub-probe -vvvv /
並瀏覽輸出內容中 GRUB 嘗試辨認的文件系統。下面這個例子中,GRUB 嘗試辨認了 ZFS , 但出現了如下輸出:
grub-probe -vvvv /
(...) grub-core/kern/fs.c:56: Detecting zfs... grub-core/osdep/hostdisk.c:420: opening the device `/dev/sda4' in open_device() grub-core/fs/zfs/zfs.c:1199: label ok 0 grub-core/osdep/hostdisk.c:399: reusing open device `/dev/sda4' grub-core/fs/zfs/zfs.c:1014: check 2 passed grub-core/fs/zfs/zfs.c:1025: check 3 passed grub-core/fs/zfs/zfs.c:1032: check 4 passed grub-core/fs/zfs/zfs.c:1042: check 6 passed grub-core/fs/zfs/zfs.c:1050: check 7 passed grub-core/fs/zfs/zfs.c:1061: check 8 passed grub-core/fs/zfs/zfs.c:1071: check 9 passed grub-core/fs/zfs/zfs.c:1093: check 11 passed grub-core/fs/zfs/zfs.c:1119: check 10 passed grub-core/fs/zfs/zfs.c:1135: str=com.delphix:hole_birth grub-core/fs/zfs/zfs.c:1135: str=com.delphix:embedded_data grub-core/fs/zfs/zfs.c:1144: check 12 passed (feature flags) grub-core/fs/zfs/zfs.c:1884: zio_read: E 0: size 4096/4096 (...) grub-core/osdep/hostdisk.c:399: reusing open device `/dev/sda4' grub-core/fs/zfs/zfs.c:2117: zap: name = com.delphix:extensible_dataset, value = 18, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = com.datto:bookmark_v2, value = 0, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = com.datto:encryption, value = c, cd = 0 # <------------------ (檢測到啟用了原生加密功能) grub-core/kern/fs.c:78: zfs detection failed. # <---------------------------------------------------- (檢測失敗) grub-core/kern/fs.c:56: Detecting xfs... grub-core/fs/xfs.c:931: Reading sb grub-core/fs/xfs.c:270: Validating superblock grub-core/kern/fs.c:78: xfs detection failed. grub-core/kern/fs.c:56: Detecting ufs2... (...) grub-core/kern/fs.c:56: Detecting affs... grub-core/kern/fs.c:78: affs detection failed. grub-probe: error: unknown filesystem.
這說明在檢測到 com.datto:encryption
功能前,程序都在正常運行。由於 GRUB 不支持 ZFS 的原生加密功能(截止2021年8月),ZFS 檢測就失敗了。這時可以創建另一個兼容 GRUB 的存儲池用來引導加密的存儲池(截止2021年8月,這也是 OpenZFS 官方推薦的做法,參見有關的 OpenZFS 項目頁面)。
在一個兼容 GRUB 的存儲池上成功運行 grub-probe
的輸出應該類似下方:
grub-probe -vvvv /boot
(...) grub-core/osdep/hostdisk.c:399: reusing open device `/dev/sda3' grub-core/fs/zfs/zfs.c:2117: zap: name = com.delphix:extensible_dataset, value = 0, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = com.delphix:embedded_data, value = 1, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = com.delphix:hole_birth, value = 1, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = org.open-zfs:large_blocks, value = 0, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = org.illumos:lz4_compress, value = 1, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = , value = 0, cd = 0 grub-core/fs/zfs/zfs.c:2117: zap: name = , value = 0, cd = 0 grub-core/fs/zfs/zfs.c:3285: alive (...) grub-core/fs/zfs/zfs.c:1906: endian = 1 grub-core/fs/zfs/zfs.c:597: dva=8, 20008 grub-core/fs/zfs/zfs.c:2697: alive zfs
從 ZFS 上引導您的內核與 initrd[編輯 | 編輯原始碼]
如果您的內核與 initrd 保存在單獨的使用 ext4 或 vfat 等文件系統的非 ZFS /boot
分區上,您可以跳過這一步。
如果您的內核與 initrd 在 ZFS 數據集上保存,GRUB 使用的內核與 initrd 路徑應該是如下格式:
/dataset(数据集)/@/actual(实际)/path(路径)
下面是當 Arch 安裝在根數據集上時的例子:
/boot/grub/grub.cfg
set timeout=5 set default=0 menuentry "Arch Linux" { search -u UUID linux /@/boot/vmlinuz-linux zfs=zroot rw initrd /@/boot/initramfs-linux.img }
下面是當 Arch 安裝在某個子數據集上時的情況:
/boot/grub/grub.cfg
set timeout=5 set default=0 menuentry "Arch Linux" { search -u UUID linux /ROOT/default/@/boot/vmlinuz-linux zfs=zroot/ROOT/default rw initrd /ROOT/default/@/boot/initramfs-linux.img }
從單獨的引導分區啟動您的內核與 initrd[編輯 | 編輯原始碼]
這是當您的內核與 initrd 保存在一個單獨的非 ZFS 分區上且 Arch 安裝在某個子數據集上時的情況:
/boot/grub/grub.cfg
set timeout=5 set default=0 menuentry "Arch Linux" { search -u UUID linux /vmlinuz-linux zfs=zroot/ROOT/default rw initrd /initramfs-linux.img }
使用 systemd-boot[編輯 | 編輯原始碼]
systemd-boot 僅支持 UEFI 啟動且無法讀取 ZFS 存儲池:您必須將您的 /boot
目錄保存在一個單獨的 VFAT 或 ext4 分區上。
按照 systemd-boot#安裝 EFI 啟動管理器的教程將 systemd-boot 安裝在您的 EFI 系統分區上。
創建一個啟動項:
esp/loader/entries/arch.conf
title Arch Linux linux /vmlinuz-linux initrd /initramfs-linux.img options zfs=zroot/ROOT/default rw
使用 rEFInd[編輯 | 編輯原始碼]
要在 rEFInd 啟動管理器中使用 EFISTUB,refind_linux.conf
中針對 ZFS 設定的內核參數應該包含 zfs=bootfs
或 zfs=zroot
以便系統從 ZFS 啟動。無需額外設定 root
與 rootfstype
參數。
使用 ZFSBootMenu[編輯 | 編輯原始碼]
安裝 zfebootmenuAUR。
對於 UEFI[編輯 | 編輯原始碼]
安裝 efibootmgr包。若使用 ZFSBootMenu,您的 /boot
目錄必須存放在您的根文件系統中。更多信息請見啟動環境與您:孰輕孰重及 UEFI 啟動。
如果您的 ESP 還未掛載,請將其掛載。然後,配置 ZFSBootMenu:
/etc/zfsbootmenu/config.yaml
Global: ManageImages: true BootMountPoint: path_to_your_ESP ( ESP 分區掛載點) DracutConfDir: /etc/zfsbootmenu/dracut.conf.d PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d InitCPIO: true InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf Components: ImageDir: path_to_your_ESP ( ESP 分區掛載點) /EFI/zbm Versions: 3 Enabled: false syslinux: Config: /boot/syslinux/syslinux.cfg Enabled: false EFI: ImageDir: path_to_your_ESP ( ESP 分區掛載點) /EFI/zbm Versions: false Enabled: true Kernel: CommandLine: ro quiet loglevel=0
生成 ZFSBootMenu 映像:
# generate-zbm
設置啟動時的 zfs 命令行參數:
# zfs set org.zfsbootmenu:commandline="rw" zroot/ROOT
向 EFI 啟動管理器中加入 ZFSBootMenu 條目:
# efibootmgr --create --disk your_esp_disk --part your_esp_partition_number --label "ZFSBootMenu" --loader '\EFI\zbm\vmlinuz-linux.EFI' --unicode
對於 BIOS[編輯 | 編輯原始碼]
與 UEFI 相同,如果您使用 ZFSBootMenu, /boot
目錄必須存放在 zroot
存儲池內。
但您還需要需要一個 syslinux
目錄而非 efi
目錄,因為 ZFSBootMenu 依賴 Syslinux。
將您的分區掛在至 syslinux
目錄。
安裝 syslinux包 和 gptfdisk包 來獲得 GUID 分區圖支持。
拷貝 syslinux
目錄中的所有 .c32
文件:
# cp /usr/lib/syslinux/bios/*.c32 /your_location/syslinux
然後安裝啟動引導加載器:
# extlinux --install /your_location/syslinux
在這之後,繼續依照您的分區圖類型寫入 Syslinux 引導代碼 (boot code) :
- 在 #使用主啟動記錄的磁盤上應該安裝
mbr.bin
, - 在 #使用 GUID 分區圖的磁盤上應安裝
gptmbr.bin
配置 ZFSBootMenu 使用的內核啟動參數:
# zfs set org.zfsbootmenu:commandline="rw" zroot/ROOT
編輯以下文件來設置 ZFSBootMenu 的映像生成:
/etc/zfsbootmenu/config.yaml
Global: ManageImages: true BootMountPoint: path_to_your_syslinux_folder PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d InitCPIO: true InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf Components: ImageDir: path_to_your_syslinux_folder/zfsbootmenu Versions: false Enabled: true Kernel: CommandLine: ro quiet loglevel=0
然後生成 ZFSBootMenu 映像:
# generate-zbm
編輯以下的文件並將其內容替換為:
/boot/syslinux/syslinux.cfg
UI menu.c32 PROMPT 0 MENU TITLE ZFSBootMenu TIMEOUT 50 DEFAULT zfsbootmenu LABEL zfsbootmenu MENU LABEL ZFSBootMenu KERNEL /zfsbootmenu/vmlinuz-linux-bootmenu INITRD /zfsbootmenu/initramfs-bootmenu.img APPEND zfsbootmenu quiet # The following for the backup entry LABEL zfsbootmenu-backup MENU LABEL ZFSBootMenu (Backup) KERNEL /zfsbootmenu/vmlinuz-linux-bootmenu-backup INITRD /zfsbootmenu/initramfs-bootmenu-backup.img APPEND zfsbootmenu quiet
配置 systemd ZFS 掛載[編輯 | 編輯原始碼]
要確保您的系統能夠正常地重新啟動,您需要啟用 zfs.target
以便自動掛載存儲池與生成 hostid。
arch-chroot
環境中。分別為每個您想要自動掛載的存儲池執行:
# zpool set cachefile=/etc/zfs/zpool.cache pool(存储池名)
啟用 zfs.target
要在系統啟動時自動掛載 ZFS 存儲池,您需要啟用 zfs-import-cache.service
、zfs-mount.service
與 zfs-import.target
。
當根目錄文件系統為 ZFS 時,掛載根文件系統的過程中設備的 hostid 將不可用。對此有兩個解決方案。 您可以將您的 spl hostid 寫入啟動引導器的啟動內核參數中。例如向內核參數中加入 spl.spl_hostid=0x00bab10c
。要獲取您的 hostid 數字,運行 hostid
命令。
另一個(建議的)解決方案是在 /etc/hostid
內寫入一個 hostid ,然後重新生成 initramfs,這個過程中您的 hostid 將會被複製到 initramfs 映像中。要安全寫入 hostid 文件,您需要運行 zgenhostid
命令。
要使用 libc 生成的 hostid(建議的操作):
# zgenhostid $(hostid)
要使用自定義的 hostid,運行以下命令。注意,hostid 必須是8個字符的十六進制數字。
# zgenhostid deadbeef
要讓 zgenhostid 工具生成一個 hostid :
# zgenhostid
完成後別忘了重新生成 initramfs。
卸載文件系統並重新啟動[編輯 | 編輯原始碼]
我們離成功不遠了!如果您使用傳統類型的啟動引導分區,先運行:
# umount /mnt/boot
如果未使用傳統的單獨引導分區,應直接運行:
# zfs umount -a # zpool export zroot
現在,重新啟動系統。
從 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。