在 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 钩子来制作可以从 ZFS 根目录启动的 initrd。您选择使用的 initrd 工具反过来会影响用于指定 ZFS 根目录的内核参数/cmdlines 的语法。
以下是选项
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。
有 2 种选择:一种随 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/<image 名称>.efi
。 - 如果您使用 vmlinuz+initrd,请将 ESP(UEFI) 或启动分区(BIOS) 挂载到
/efi
并将 initrd 目标指向/efi/<initrd 名称>.img
。设置一个 pacman 钩子,将 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