在 ZFS 上安装 Arch Linux

出自 ArchWiki
(重定向自 Installing Arch Linux on ZFS

本文详细介绍了在 ZFS 根文件系统上安装 Arch Linux 所需的步骤。

注意: 本指南假定读者对 ZFS 有一定的了解。如果您不熟悉 ZFS,建议先阅读并理解 ZFS#概念,然后再回到本指南。在现有系统上安装 ZFS 并先试用命令也可能会有所帮助。

由于 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-dkmsAURzfs-utilsAUR 可能与您可能希望对 Archiso 镜像执行的其他修改具有最广泛的兼容性。继续设置自定义本地仓库在新配置文件的 Pacman 配置中包含结果仓库

在要安装的软件包列表中包含构建的软件包。下面的示例假定您只想包含 zfs-dkmsAURzfs-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
注意: 如果您稍后在运行 modprobe zfs 时遇到问题,您应该在 packages.x86_64 中包含 linux-headers。

完成

无论您从哪里获取 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-poscatarchlinuxcn 发货,另一种随 mkinitcpio-sd-zfsAUR[损坏的链接:未找到软件包] 发货。前者正在积极维护,而后者似乎已被放弃。

zfs-utils-poscat

要配置此 hook,只需将其添加到 mkinitcpio.confHOOKS 数组中的任何位置。典型的配置可能如下所示

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,它仅导入指定的池,然后将指定的数据集挂载为根目录。
注意: sd-zfs 不支持 zfs 原生加密
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 之外的所有启动引导器都无法从 ZFS 文件系统读取文件,这意味着除非您使用 grub2,否则您需要将 UKI 或 vmlinuz+initrd 放在单独的文件系统中,该文件系统可由您选择的启动引导器读取。当使用 UEFI 启动时,您可以重复使用您的 ESP 来存储它们(事实上,建议将您的 UKI 放在 ESP 中),只需记住为您的 ESP 保留足够的空间

使用 GRUB2

Grub2 能够读取 ZFS 文件系统,前提是池的创建仅启用了有限的功能集(请参阅 ZFS#GRUB 兼容的池创建),因此在使用 Grub2 时,可以将 UKI/initrd 放在 ZFS 根目录上。

警告: 考虑到 UKI/initrd 应该可以从 ZFS 根目录完全重建(请参阅 #支持完整系统回滚的布局),将 UKI/initrd 放在 ZFS 根目录上是否能实现很多目标值得怀疑。此外,Grub2 的 ZFS 实现完全独立于 OpenZFS 实现,其可靠性尚不为人知。

分区目标驱动器

分区与其他文件系统类似。有关使用哪种布局以及如何分区磁盘,请参阅前面提到的分区页面或安装指南

注意: ZFS 不支持交换文件,并且使用 zvol 进行交换存在明显的缺点:系统可能在内存压力过大的情况下死锁,并且无法休眠到 zvol 交换分区。因此,建议使用单独的交换分区。

支持完整系统回滚的布局

为了能够使用 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 缓存。这需要

  1. 在 Live CD 上启用 zfs-zed.service
  2. 使用 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#创建数据集。以下是在选择数据集选项和布局时的一些注意事项

  1. 大多数属性都从父数据集继承到子数据集,除非显式覆盖。
  2. 子项的 mountpoint 属性的默认值为 <父项的挂载点>/<子项的名称>

安装和配置 Arch Linux

按照安装指南#安装中的步骤进行操作,直到重启之前。您可能应该使用 linux-lts 内核而不是 linux

安装 ZFS

按照 ZFS#安装 安装 ZFS。

配置 ZFS

按照 ZFS#配置 配置 ZFS 相关服务。但请注意

  1. 我们处于 chroot 环境中,因此不要尝试启动 systemd 服务,只需启用它们。
  2. 跳过 ZFS#zfs-mount-generator 中的所有步骤,除了启用 zfs-zed.service。我们稍后会填充缓存。

设置 initrd

请参阅 #Initrd 工具 以配置您选择的 initrd 生成器。不要忘记通过 mkinitcpio -Pdracut --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