在 ZFS 上安装 Arch Linux
本文详细介绍了在 ZFS 根文件系统上安装 Arch Linux 所需的步骤。
由于 ZFS 内核模块是树外模块(即未包含在主线内核中),并且 Arch Linux 是滚动发布发行版,因此通常会有一段短暂的时间,外部仓库中的内核特定软件包与 Arch 仓库中的软件包不同步。这有时会导致 ZFS 模块(DKMS 软件包)无法使用最新的内核进行编译。如果您始终希望使用最新的内核软件包,那么在 ZFS 上安装 Arch 可能不是理想的选择。
有关可能的解决方案,请参阅 ZFS#安装。
获取安装介质
要在 ZFS 上安装 Arch Linux,您需要使用包含 ZFS 模块的安装介质。最简单的方法是使用替代 ISO(假设您信任此类 ISO)。您也可以使用其他支持 ZFS 的发行版的 ISO,例如 Ubuntu 或 NixOS,或创建自定义镜像(见下文)。
使用包含 ZFS 模块的非官方 archiso
存在一个非官方的 archiso,可以直接使用,而无需手动创建整个镜像或在启动后添加 ZFS 模块。但请注意,它仅包含 linux-lts 内核和 zfs-linux-lts 模块。
请参阅 r-maerz/archlinux-lts-zfs。
使用其他发行版的 ISO
您也可以选择具有内置 ZFS 模块的 ISO 的发行版,因为大多数发行版都应该打包了 arch-install-scripts。例如,Ubuntu ISO 和 NixOS ISO 应该都可以正常工作。只需记住根据需要更改或跳过安装指南中的某些步骤,例如网络配置。
将 ZFS 模块嵌入到自定义 archiso 中
按照 Archiso 步骤创建功能齐全的 Arch Linux Live CD/DVD/USB 镜像。要在镜像中包含 ZFS 支持,您可以从 AUR 构建您选择的 PKGBUILD,或者包含来自非官方用户仓库的预构建软件包。
使用来自 AUR 的自构建 ZFS 软件包
按照常规步骤构建您想要的 ZFS 软件包。如果您不确定,zfs-dkmsAUR 和 zfs-utilsAUR 可能与您可能希望对 Archiso 镜像执行的其他修改具有最广泛的兼容性。继续设置自定义本地仓库。在新配置文件的 Pacman 配置中包含结果仓库。
在要安装的软件包列表中包含构建的软件包。下面的示例假定您只想包含 zfs-dkmsAUR 和 zfs-utilsAUR 软件包。
packages.x86_64
... zfs-dkms zfs-utils
如果您包含任何 DKMS 软件包,请确保您还包含 ISO 中包含的任何内核的标头(默认内核的 linux-headers)。
使用 archzfs 非官方用户仓库
将 archzfs 非官方用户仓库添加到新 Archiso 配置文件中的 pacman.conf
。
将 archzfs-linux
组添加到要安装的软件包列表中(archzfs
仓库仅提供 x86_64 架构的软件包)。
packages.x86_64
... archzfs-linux
完成
无论您从哪里获取 ZFS 软件包,您都应该完成构建 ISO。
选择启动方法
由于您选择使用的 initrd 工具和启动引导器会影响安装过程的后续步骤,因此您应该在继续安装之前决定使用它们的哪些组合。
Initrd 工具
默认情况下,dracut 和 mkinitcpio 都不支持从 ZFS 根目录启动,因为它们不包含 initrd 中必要的内核模块和用户空间工具。您需要使用 dracut 模块或 mkinitcpio hook 来制作可以从 ZFS 根目录启动的 initrd。您选择使用的 initrd 工具反过来会影响内核参数/cmdlines 的语法,用于指定 ZFS 根目录。
以下是选项
zfs hook
使用默认的基于 busybox 的 initrd 时,zfs
hook 是唯一的选择。
要配置 zfs
hook,只需在 mkinitcpio.conf(5) 中 filesystems
hook 之前添加 zfs
可能的内核参数语法为
root=zfs
,它使用bootfs
属性确定根文件系统root=ZFS=<pool/dataset>
,它使用池或数据集作为根目录。当指定池时,根文件系统根据mountpoint
属性确定zfs=auto
:与root=zfs
效果相同zfs=<pool/dataset>
:与root=ZFS=<pool/dataset>
效果相同
此外,可以设置以下内核参数来调整 initrd 的行为
zfs_force=1
使zpool import
命令使用-f
标志zfs_wait=<seconds>
在运行zpool import
之前等待设备出现
sd-zfs hook
zfs
hook 与基于 systemd 的 initrd 不兼容。相反,您应该使用 sd-zfs
hook。
有两种选择:一种随 zfs-utils-poscat 从 archlinuxcn 发货,另一种随 mkinitcpio-sd-zfsAUR[损坏的链接:未找到软件包] 发货。前者正在积极维护,而后者似乎已被放弃。
zfs-utils-poscat
要配置此 hook,只需将其添加到 mkinitcpio.conf
的 HOOKS
数组中的任何位置。典型的配置可能如下所示
HOOKS=(systemd sd-zfs autodetect microcode modconf kms keyboard sd-vconsole block filesystems fsck)
支持的 cmdline 格式为
root=zfs
,它在 initrd 中导入所有池,搜索第一个设置了 bootfs 属性的池,然后将 bootfs 挂载为根目录。root=zfs:poolname
,它仅导入指定的池,然后将池的 bootfs 挂载为根目录。root=zfs:poolname/dataset
,它仅导入指定的池,然后将指定的数据集挂载为根目录。
mkinitcpio-sd-zfs
有关配置的文档,请参阅github 仓库。
zfs module
如果相反您想使用 dracut 进行 initrd,那么您应该使用 zfs-utilsAUR 附带的 zfs
dracut 模块。查看文档 https://openzfs.github.io/openzfs-docs/man/master/7/dracut.zfs.7.html,了解如何配置 zfs 模块。
启动引导器
由于导入 ZFS 池、挂载根文件系统和 pivot_root
到新根目录的任务都由 UKI 或 vmlinuz+initrd 处理,因此对您可以使用的启动引导器没有任何要求。实际上,即使是 EFI 启动存根 也应该足够了,前提是内核参数配置正确,具体取决于您用于 initrd 的工具(请参阅上面的 #Initrd 工具 部分)
使用 GRUB2
Grub2 能够读取 ZFS 文件系统,前提是池的创建仅启用了有限的功能集(请参阅 ZFS#GRUB 兼容的池创建),因此在使用 Grub2 时,可以将 UKI/initrd 放在 ZFS 根目录上。
分区目标驱动器
分区与其他文件系统类似。有关使用哪种布局以及如何分区磁盘,请参阅前面提到的分区页面或安装指南。
支持完整系统回滚的布局
为了能够使用 ZFS 快照所有内容,您需要重建 UKI 或 vmlinuz+initrd(以便您可以回滚完整的系统状态),您可以使用以下分区布局
- 不要在
/boot
上挂载任何内容,这样 vmlinuz 就放置在您的根目录上,这是一个 ZFS 文件系统。 - 如果您使用 UKI,请将 ESP 挂载到
/efi
,并将 UKI 目标指向/efi/EFI/Linux/<镜像名称>.efi
。 - 如果您使用 vmlinuz+initrd,请将 ESP(UEFI) 或启动分区(BIOS) 挂载到
/efi
,并将 initrd 目标指向/efi/<initrd 名称>.img
。设置一个 pacman hook,自动将 vmlinuz 从/boot/vmlinuz-*
复制到/efi/
。
要执行回滚,只需回滚您的 ZFS 根文件系统,然后重新生成您的 UKI 或重新生成 initrd,然后手动将 vmlinuz 从 /boot/vmlinuz-*
复制到 /efi/
。
设置 ZFS 文件系统
在 Live CD 上启用 ZED
由于本指南假定使用 zfs-mount-generator(8),我们需要在首次启动到我们的系统之前生成 zfs-list
缓存。这需要
- 在 Live CD 上启用
zfs-zed.service
。 - 使用
touch
为您打算创建的每个池在/etc/zfs/zfs-list.cache/<池名称>
创建空文件
创建根池
有关详细信息,请参阅 ZFS#创建 ZFS 池。例如,以下命令在分区 /dev/nvme0n1p2
上创建一个名为 rpool
的根池,并将 altroot
属性设置为 /mnt
# zpool create \ -O acltype=posixacl \ -O relatime=on \ -O dnodesize=auto \ -O normalization=formD \ -O compression=zstd \ -O mountpoint=/ \ -R /mnt \ rpool /dev/nvme0n1p2
altroot
属性,该属性通过池创建或导入期间的 -R
标志设置,以临时向挂载点添加前缀,以避免遮蔽 Live CD 环境创建文件系统
有关详细信息,请参阅 ZFS#创建数据集。以下是在选择数据集选项和布局时的一些注意事项
- 大多数属性都从父数据集继承到子数据集,除非显式覆盖。
- 子项的
mountpoint
属性的默认值为<父项的挂载点>/<子项的名称>
。
安装和配置 Arch Linux
按照安装指南#安装中的步骤进行操作,直到重启之前。您可能应该使用 linux-lts 内核而不是 linux。
安装 ZFS
按照 ZFS#安装 安装 ZFS。
配置 ZFS
按照 ZFS#配置 配置 ZFS 相关服务。但请注意
- 我们处于 chroot 环境中,因此不要尝试启动 systemd 服务,只需启用它们。
- 跳过 ZFS#zfs-mount-generator 中的所有步骤,除了启用
zfs-zed.service
。我们稍后会填充缓存。
设置 initrd
请参阅 #Initrd 工具 以配置您选择的 initrd 生成器。不要忘记通过 mkinitcpio -P
或 dracut --regenerate-all
重新生成 initrd。
填充 zfs-list 缓存
现在退出 chroot。将 /etc/zfs/zfs-list.cache
复制到 /mnt/etc/zfs/zfs-list.cache
# cp -r /etc/zfs/zfs-list.cache /mnt/etc/zfs/
这提供了 zfs-mount-generator
所需的缓存。
卸载、导出并重启
卸载所有已挂载的文件系统(假设 altroot
为 /mnt
)
# umount -R /mnt
导出所有池
# zpool export -a
重启
# reboot