构建以 ZFS 为根文件系统的 openSUSE Tumbleweed
概览
注意事项
本教程使用整块物理磁盘。
本教程不适用于双系统。
备份你的数据。一切既有数据都将丢失。
这不是 openSUSE 官方教程。如果后续 openSUSE 新增了 Root on ZFS 的支持,本文档将会更新。此外,openSUSE 的默认系统安装器 YaST2 不支持 zfs。本教程在不使用 YaST2 的情况下通过 zypper 设置系统的方法,基于社区中人员经验所撰写的 openSUSE 安装方法。有关更多信息,请查看外部链接。
系统要求
在提供 4 KiB 逻辑扇区(“4Kn”)的驱动器上进行的安装仅在使用 UEFI 启动时可行。这并非 ZFS 独有的问题。在 4Kn 磁盘上使用传统(BIOS)启动时,GRUB 不能也不会工作。
在内存少于 2 GiB 的计算机运行 ZFS 时,存在严重的性能瓶颈。对于基础工作负载,建议至少使用 4 GiB 内存以获得正常性能。如果你希望使用去重功能,将需要大量的内存。启用去重是一项永久性更改,无法轻易还原。
支持
如果你需要帮助,可以通过 邮件列表 或在 Libera Chat 上的 IRC 频道 #zfsonlinux 联系社区。如果你有与本教程相关的 Bug 报告或功能请求,请提交新的 issue,并 @Zaryob。
加密
本指南支持三种不同的加密方案:未加密、ZFS 原生加密、以及 LUKS。无论选择哪一种,都能完全使用一切 ZFS 特性。
未加密当然不会加密任何内容。在没有进行任何加密的情况下,该方案自然具有最佳性能。
ZFS 原生加密会对根池中的数据和大多数元数据进行加密。它不会加密数据集或快照的名称或属性。启动池完全不加密,但其中只包含 bootloader、kernel 和 initrd。(除非你在 /etc/fstab 中放置了密码,否则 initrd 不太可能包含敏感数据。)系统在未在控制台输入口令的情况下无法启动。性能良好。由于加密是在 ZFS 内部完成的,即使使用了多个磁盘(mirror 或 raidz 拓扑),数据也只需要加密一次。
LUKS 会加密几乎所有内容。唯一未加密的数据是 bootloader、kernel 和 initrd。系统在未在控制台输入口令的情况下无法启动。性能良好,但 LUKS 位于 ZFS 底层,因此如果使用了多个磁盘(mirror 或 raidz 拓扑),数据需要在每个磁盘上各加密一次。
第 1 步:准备安装环境
启动 openSUSE Live CD。如果出现提示,请使用用户名
live登录,密码live。根据需要将系统连接到互联网(例如加入你的 WiFi 网络)。打开终端。设置更新软件仓库:
可选:在 Live CD 环境中安装并启动 OpenSSH 服务器: 如果你有第二台系统,使用 SSH 访问目标系统会更加方便:
提示:
你可以使用
ip addr show scope global | grep inet查找你的 IP 地址。然后,在你的主机上,通过ssh user@IP进行连接。禁用自动挂载: 如果磁盘之前被使用过(在相同偏移位置存在分区),在未禁用的情况下,先前的文件系统(例如 ESP)会被自动挂载:
切换为 root:
在 Live CD 环境中安装 ZFS:
第 2 步:格式化磁盘
设置磁盘变量:
在 ZFS 中始终使用长别名
/dev/disk/by-id/*。直接使用设备节点/dev/sd*可能导致偶发的导入失败,尤其是在系统中存在多个存储池时。提示:
ls -la /dev/disk/by-id会列出别名。你是在虚拟机中操作吗?如果虚拟磁盘在
/dev/disk/by-id中缺失,使用 KVM virtio 时可用/dev/vda;否则,请参考故障排查部分。
如果重复使用磁盘,根据需要清理: 如果磁盘之前用于 MD 阵列:
清除分区表:
如果收到内核仍在使用旧分区表的提示,可以请求内核重新加载分区信息:
如果新分区仍未显示,可重启并重新开始(此步骤可跳过)。
分区你的磁盘: 如果需要传统(BIOS)启动,运行:
如果需要 UEFI 启动(现在或将来使用),运行:
为启动池创建分区:
选择以下之一:
未加密或 ZFS 原生加密:
LUKS:
如果创建镜像或 raidz 拓扑,请对将加入池的所有磁盘重复分区命令。
创建启动池:
对启动池无需自定义选项。
GRUB 不支持全部的 zpool 功能。请参见 grub-core/fs/zfs/zfs.c 中的
spa_feature_names。 此步骤为/boot创建了独立的启动池,其功能仅限于 GRUB 支持的功能,从而能够让根池使用任意功能。注意 GRUB 以只读方式打开池,因此所有只读兼容功能均被 GRUB“支持”。提示:
如果创建镜像拓扑,请使用:
对于 raidz 拓扑,将上面命令中的
mirror替换为raidz、raidz2或raidz3,并列出其他磁盘的分区。池名称可自定义。若更改,新名称必须保持一致使用。
bpool命名约定来源于本教程。
功能说明:
allocation_classes功能安全可用。但除非使用它(如specialvdev),否则启用它无意义。几乎不会有人在启动池使用该功能。如果关注启动池速度,将整个池放在更快的磁盘上比使用specialvdev 更合理。project_quota功能经过测试,安全可用。对启动池而言几乎无实际意义。resilver_defer功能安全,但启动池容量较小,通常无需使用。spacemap_v2功能经过测试,安全可用。启动池容量较小,实际影响不大。作为只读兼容功能,
userobj_accounting理论上兼容,但在实践中 GRUB 可能报错“invalid dnode type”。此功能对/boot无关紧要。
创建根池: 选择以下方案之一:
未加密:
ZFS 原生加密:
LUKS:
备注:
这里推荐使用
ashift=12,因为如今许多硬盘的物理扇区为 4 KiB(或更大),即使它们显示为 512 B 的逻辑扇区。此外,未来更换的硬盘可能是 4 KiB 物理扇区(此时ashift=12是可取的)或 4 KiB 逻辑扇区(此时ashift=12是必须的)。设置
-O acltype=posixacl可全局启用 POSIX ACL。如果不想启用此选项,可删除它,但随后需要在/var/log的zfs create中添加-o acltype=posixacl(注意小写“o”),因为 journald 需要 ACL。设置
normalization=formD可消除一些与 UTF-8 文件名规范化相关的极端情况。它还隐含utf8only=on,意味着只允许 UTF-8 文件名。如果你希望支持非 UTF-8 文件名,请不要使用此选项。关于强制仅使用 UTF-8 文件名可能存在的问题,请参见 The problems with enforced UTF-8 only filenames。设置
relatime=on在经典 POSIXatime行为(性能影响显著)与atime=off(完全禁用 atime 更新来获得最佳性能)之间提供折中。自 Linux 2.6.30 起,relatime成为其他文件系统的默认设置。更多信息请参见 RedHat 文档。设置
xattr=sa大幅提高扩展属性的性能。在 ZFS 内部,扩展属性用于实现 POSIX ACL。扩展属性也可被用户空间应用使用,一些桌面 GUI 应用会使用它们;Samba 可使用它们存储 Windows ACL 和 DOS 属性;Samba Active Directory 域控制器需要它们。注意xattr=sa是 Linux 特定 的。如果将xattr=sa池迁移到 ZFS-on-Linux 以外的 OpenZFS 实现,扩展属性将无法读取(数据仍可用)。如果扩展属性的可移植性对你重要,请省略上面的-O xattr=sa。即便不希望整个池使用xattr=sa,在/var/log上使用通常是安全的。确保包括驱动路径的
-part4部分。如果忘记,将指定整个磁盘,ZFS 会重新分区,你将丢失启动器分区。ZFS 原生加密 现 默认使用
aes-256-gcm。对于 LUKS,选择的密钥大小为 512 位。但 XTS 模式需要两个密钥,因此 LUKS 密钥被一分为二。因此
-s 512即表示 AES-256。你的口令很可能是最薄弱环节。请谨慎选择。参考 cryptsetup FAQ 第 5 节 获取指导。
提示:
如果你创建镜像拓扑,请使用以下命令创建池:
对于 raidz 拓扑,将上面命令中的
mirror替换为raidz、raidz2或raidz3,并列出其他磁盘的分区。使用 LUKS 配合镜像或 raidz 拓扑时,请使用
/dev/mapper/luks1、/dev/mapper/luks2等,这些需要通过cryptsetup创建。可自定义存储池名称。如果更改,新名称必须保持一致。在可以自动安装到 ZFS 的系统中,根池默认命名为
rpool。
第 3 步:安装系统
创建用于容器的文件系统数据集:
在 Solaris 系统中,根文件系统会被克隆,并通过
pkg image-update或beadm对后缀进行递增以应对重大系统更改。类似功能已在 Ubuntu 20.04 中通过zsys工具实现,尽管其数据集布局更复杂。即使没有此类工具,仍可手动创建 rpool/ROOT 和 bpool/BOOT 容器的克隆。不过,为简化操作,本教程假设/boot使用单一文件系统。为根文件系统和启动文件系统创建数据集:
对于 ZFS,通常不需要使用挂载命令(
mount或zfs mount)。此处因canmount=noauto属于例外情况。创建其他数据集:
以下数据集为可选,取决于你的偏好及软件选择。 如果希望这些数据集不被快照:
如果系统使用
/opt:如果系统使用
/srv:如果系统使用
/usr/local:如果系统将安装游戏:
如果系统将存储本地邮件在
/var/mail:如果系统将使用 Snap 包:
如果系统将使用 Flatpak 包:
如果系统使用
/var/www:如果系统使用 GNOME:
如果系统使用 Docker(自行管理数据集和快照):
如果系统使用 NFS(锁定):
在
/run挂载 tmpfs:后续推荐使用 tmpfs,但如果希望为
/tmp创建独立数据集:此数据集布局的主要目标是将操作系统与用户数据分离,从而可回滚根文件系统而不影响用户数据。
如果不做额外操作,
/tmp将作为根文件系统的一部分存储。或者,可以如上创建独立的/tmp数据集,将/tmp数据排除在根文件系统快照之外。同时,可对rpool/tmp设置配额以限制最大使用空间。否则,可在后续使用 tmpfs(内存文件系统)。复制
zpool.cache:
第 4 步:安装系统
将软件源添加到 chroot 目录:
生成软件源索引:
你会收到指纹异常提示,输入
a表示始终信任并继续:使用 zypper 安装 openSUSE Tumbleweed: 如果只安装基本的 pattern,zypper 会安装 busybox-grep,从而屏蔽默认内核包。因此建议新手安装 enhanced_base pattern。但 enhanced_base 包含的冗余包可能会在服务器环境中带来困扰。你需要根据用途选择:
使用 zypper 安装 openSUSE Tumbleweed 的基础包(推荐服务器环境):
使用 zypper 安装 openSUSE Tumbleweed 的增强基础包(推荐桌面环境):
在 chroot 中安装 openSUSE zypper 包管理系统:
推荐:在 chroot 中安装 openSUSE YaST2 系统:
注意
如果你的
/etc/resolv.conf文件为空,请执行以下命令:这将方便初学者配置网络及其他系统设置。
如需安装桌面环境,请参见 openSUSE wiki。
第 5 步:系统配置
配置主机名: 将
HOSTNAME替换为你希望使用的主机名:添加一行:
或者,如果系统在 DNS 中有完整域名:
提示:
如果觉得
vi难用,可以使用nano。复制网络信息:
将使用 YaST2 重新配置网络。
注意
如果你的
/etc/resolv.conf文件为空,请执行以下命令:将 LiveCD 环境的虚拟文件系统绑定到新系统并进入 chroot:
注意:
此处使用的是
--rbind而非--bind。配置基本系统环境:
即使你偏好非英语系统语言,也要确保
en_US.UTF-8可用:输出中必须包含以下语言:
C
C.UTF-8
en_US.utf8
POSIX
从
locale -a输出中找到所需语言,然后执行:可选:重新安装以增强稳定性: 安装后可能需要重新安装某些软件包以修复小问题。openSUSE 没有类似
dpkg-reconfigure的命令,可用zypper install -f替代:安装内核:
注意:
如果安装了 base pattern,需要卸载 busybox-grep 才能安装 kernel-default 包。
在 chroot 环境中为新系统安装 ZFS:
如果系统使用 UEFI 和安全启动,自 Linux 5.4 起,内核要求所有内核模块必须经过签名。
filesystems项目中的 ZFS 内核模块已签名,但不是系统首次启动时自动注册的官方 openSUSE 密钥。为了确保系统信任该签名密钥,请安装:下次启动时,MOK 会提示你注册新密钥。
仅对 LUKS 安装:配置
/etc/crypttab:使用
initramfs是为了解决 cryptsetup 不支持 ZFS 的问题。提示:
如果创建 mirror 或 raidz 拓扑,为
luks2等磁盘重复添加/etc/crypttab条目。仅对 LUKS 安装:修正 ZFS 的 cryptsetup 命名:
安装 GRUB: 选择一种启动方式:
安装 GRUB 用于 legacy(BIOS)启动:
安装 GRUB 用于 UEFI 启动:
注意:
对于 4Kn 驱动器,
-s 1是为满足 FAT32 最小簇大小(512 MiB 分区)要求。512 B 扇区的驱动器也可正常使用。对于 mirror 或 raidz 拓扑,这一步只在第一块磁盘上安装 GRUB,其他磁盘在稍后处理。
可选:移除 os-prober:
仅在双系统环境中需要 os-prober,否则可避免 update-bootloader 报错。
设置 root 密码:
启用 bpool 导入:
确保始终导入
bpool,无论是否存在/etc/zfs/zpool.cache,是否启用zfs-import-scan.service。内容如下:
可选(但推荐):将
/tmp挂载为 tmpfs如果之前创建了
/tmp数据集,则跳过此步,否则可以通过启用tmp.mount单元将/tmp放在 tmpfs(内存文件系统)上:
第 6 步:内核安装
将 zfs 模块添加到 dracut:
刷新内核文件:
刷新 initrd 文件:
注意:
在某些设备中,dracut 可能无法识别 LUKS 分区,会出现报错“Failure occurred during following action: configuring encrypted DM device X VOLUME_CRYPTSETUP_FAILED” 。 解决方法:检查 cryptsetup 的安装情况。详细信息
注意:
即使已将 zfs 配置添加到系统模块
/etc/modules.d,若 dracut 未识别,仍需强制添加:
第 7 步:安装 Grub2
验证 ZFS 启动文件系统的识别情况:
输出必须为
zfs。如果
grub2-probe命令出现问题,可执行:然后返回执行
grub2-probe步骤。解决 GRUB 缺少 zpool-features 支持的方法:
可选(但强烈建议):便于调试 GRUB:
删除
GRUB_CMDLINE_LINUX_DEFAULT中的quiet取消注释:
GRUB_TERMINAL=console保存并退出
系统重启两次并确认一切正常后,可根据需要恢复这些更改。
更新启动配置:
注意:
如果出现
os-prober错误可忽略。注意:
如果安装 grub2 时出现问题,可考虑使用 systemd-boot。
注意:
如果命令无输出,可使用经典的
grub.cfg生成:安装启动加载器:
对于 legacy(BIOS)启动,将 GRUB 安装到 MBR:
注意
这里是将 GRUB 安装到整个磁盘,而非单个分区。
如果创建了 mirror 或 raidz 拓扑,需要对池中每块磁盘重复执行该命令。
对于 UEFI 启动,将 GRUB 安装到 ESP 分区:
不需要指定磁盘。如果创建了 mirror 或 raidz 拓扑,额外磁盘稍后处理。
第 8 步:Systemd-Boot 安装
警告:
这将破坏你的 YaST2 启动加载器配置。仅在无法通过 grub2 修复问题时才使用此方法。本步骤是为某些情况下 grub2 无法识别 rpool 池而提供的替代方案。
安装 systemd-boot:
配置启动加载器:
创建启动项:
复制内核和 initrd 文件到 EFI 分区:
更新 systemd-boot 变量:
第 9 步:文件系统配置
修复文件系统挂载顺序:
激活
zfs-mount-generator,让 systemd 识别各个挂载点,这对/var/log、/var/tmp等目录至关重要。rsyslog.service会依赖var-log.mount,使用 systemdPrivateTmp特性的服务会自动依赖var-tmp.mount。验证
zed是否更新了缓存,确保以下文件非空:如果文件为空,强制更新缓存并重新检查:
如果仍为空,先停止
zed:然后重新启动
zed并重试。修正缓存路径,去掉前缀
/mnt:
第 10 步:首次启动
可选:安装 SSH 服务:
可选:对初始安装创建快照:
以后在每次升级前,你可能希望先创建快照,并在适当的时候删除旧快照(包括这个初始快照)以节省空间。
退出
chroot环境,返回 LiveCD 环境:在 LiveCD 环境中执行以下命令卸载所有文件系统:
重启系统:
等待新安装的系统正常启动,并以 root 登录。
创建用户账户: 将
用户名替换为你希望的用户名:镜像安装 GRUB(多磁盘安装时):
如果系统安装在多个磁盘上,需要在其他磁盘上重复安装 GRUB。
对于 legacy(BIOS)启动:先确认当前是否为 EFI 模式:
输出必须包含
legacy_boot。然后重新配置 GRUB:按回车直到出现设备选择界面,使用空格键选择池中的所有磁盘(不是分区)。
对于 UEFI 启动:
对第二块及后续磁盘(将 debian-2 改为 -3 等):
第 11 步(可选):配置 Swap
注意:
在内存压力极高的系统上,无论 swap 空间剩余多少,使用 zvol 作为 swap 设备都可能导致系统锁死。上游已有相关 bug 报告。
创建用于 swap 的 zvol(卷数据集):
你可以根据需求调整大小(这里为
4G)。压缩算法使用
zle,因为这是开销最小的算法。由于本指南推荐ashift=12(磁盘上 4 KiB 块),4 KiB 页面大小情况下,没有压缩算法能减少 I/O。唯一例外是全零页面,会被 ZFS 丢弃,但必须启用某种压缩才能实现这一行为。配置 swap 设备:
注意:
在配置文件中始终使用完整
/dev/zvol别名,切勿使用短设备名/dev/zdX。RESUME=none用于禁用休眠恢复。由于 zvol 在启动时尚未导入(池未导入),恢复脚本无法找到 swap,如果不禁用,启动过程会停滞约 30 秒等待 swap zvol 出现。启用 swap 设备:
第 12 步:最终清理
等待系统正常启动,使用你创建的用户账号登录。确保系统(包括网络)工作正常。
可选:删除初始安装的快照:
可选:禁用 root 密码:
可选(强烈建议):禁用 root SSH 登录:
如果之前安装过 SSH,请撤销临时修改:
可选:重新启用图形启动过程:
如果你希望使用图形启动,并且使用了 LUKS,这可以让提示界面更美观。
注意:
如果出现
osprober错误,可忽略。可选:仅针对 LUKS 安装,备份 LUKS 头:
将备份妥善保存(如云端存储)。该备份受 LUKS 密码保护,但你也可选择额外加密。
提示:
如果创建了镜像或 raidz 拓扑,请对每个 LUKS 卷重复此操作(如
luks2等)。
故障排除
使用 Live CD 进行救援
请参考 第 1 步:准备安装环境。
对于 LUKS 安装,首先解锁磁盘:
正确挂载所有文件系统:
如有需要,可以进入已安装的系统环境进行 chroot:
进行必要的修复操作。
完成后,进行清理:
Areca
需要 arcsas blob 驱动的系统应将其添加到 /etc/initramfs-tools/modules 文件中,然后运行:
如果内核日志中出现类似以下信息:
请升级或降级 Areca 驱动。在出现此错误的系统上 ZoL 将不稳定。
MPT2SAS
本教程中大多数问题报告都与 mpt2sas 硬件相关,这类硬件会延迟异步初始化驱动器,例如某些 IBM M1015 或已刷回参考 LSI 固件的 OEM 卡。
基本问题是,这些控制器上的磁盘在 Linux 内核启动时不可见,而 ZoL 不支持热插拔池成员。详见:https://github.com/zfsonlinux/zfs/issues/330。
大多数 LSI 卡完全兼容 ZoL。如果你的 LSI 卡存在此问题,可在 /etc/default/zfs 中设置:
系统将在导入池之前等待 X 秒,确保所有磁盘都已出现。
QEMU/KVM/XEN
为每个虚拟磁盘设置唯一序列号(使用 libvirt 或 qemu,例如:-drive if=none,id=disk1,file=disk1.qcow2,serial=1234567890)。
要在虚拟机中使用 UEFI(而不仅仅是 BIOS 启动),请在宿主机上执行:
取消对以下行的注释:
重启 libvirt 服务:
VMware
在虚拟机的
.vmx文件或 vSphere 配置中设置:
这样可以确保在客机中创建别名 /dev/disk。
外部链接
最后更新于