构建以 ZFS 为根文件系统的 Debian 9 (Stretch)
概述
有更新版本
新安装请参阅《根文件系统使用 ZFS 的 Debian 10 Buster》。
注意事项
本教程将使用整块物理磁盘。
本教程不适用于双系统环境。
请先备份数据。现有数据都将被清除。
系统要求
强烈建议使用 64-bit 内核。
在逻辑扇区为 4 KiB(“4Kn”磁盘)的磁盘上安装,仅在 UEFI 启动模式下可行。这并非 ZFS 特有。GRUB 在 legacy(BIOS)启动模式下无法也不会支持 4K 扇区。
内存小于 2 GiB 的计算机运行 ZFS 时会非常缓慢。在基础工作负载下,建议至少 4 GiB 内存,才能获得正常性能。如果你希望使用去重(deduplication),则需要大量内存。启用去重是不可逆的永久性更改,无法轻易恢复。
加密
本指南支持两种加密方案:未加密和 LUKS(全盘加密)。ZFS 原生加密尚未发布。无论选择何种方式,所有 ZFS 功能均可完全使用。
未加密当然不会对任何数据进行加密。在没有加密开销的情况下,该方案自然具有最佳性能。
LUKS 会对几乎所有内容进行加密:操作系统、交换分区、用户主目录以及其他数据。唯一未加密的数据是引导加载程序、内核和 initrd。系统启动时必须在控制台输入密码,否则无法启动。性能表现良好,但 LUKS 位于 ZFS 下层,因此如果使用多块磁盘(镜像或 raidz 拓扑),每个磁盘上的数据都需要单独加密一次。
第一步:准备安装环境
1.1 启动 Debian GNU/Linux Live CD。如果出现提示,请使用用户名 user 和密码 live 进行登录。根据需要将系统连接到互联网(例如接入你的 WiFi 网络)。
1.2 可选:在 Live CD 环境中安装并启动 OpenSSH 服务器:
如果你有第二台设备,通过 SSH 访问目标系统会很方便。
提示: 可以使用 ip addr show scope global | grep inet 查找你的 IP 地址。然后,从主机通过 ssh user@IP 连接。
1.3 切换为 root 用户:
1.4 设置,更新软件源:
1.5 在 Live CD 环境中安装 ZFS:
dkms 依赖项是手动安装的,以确保来自 stretch 而不是 stretch-backports。这并非关键步骤。
第二步:磁盘格式化
2.1 如果重复使用磁盘,根据需要清理:
2.2 对磁盘进行分区:
选择以下其中任一方案:
2.2a 不加密:
2.2b LUKS 加密:
在 ZFS 中始终使用长的别名 /dev/disk/by-id/*。直接使用设备节点 /dev/sd* 可能导致间歇性导入失败,尤其是在系统中存在多个存储池的情况下。
提示:
使用命令
ls -la /dev/disk/by-id可以列出别名。你是在虚拟机中操作吗?如果虚拟磁盘在
/dev/disk/by-id中缺失,使用 KVM + virtio 时可用/dev/vda;否则请参考故障排查部分。如果你要创建镜像或 raidz 拓扑,请对 pool 中的所有磁盘重复分区命令。
2.3 创建引导存储池:
通常无需为引导存储池自定义任何选项。
GRUB 并不支持所有 ZFS 存储池特性。参见 grub-core/fs/zfs/zfs.c 中的 spa_feature_names。此步骤为 /boot 创建一个单独的引导存储池,仅启用 GRUB 支持的特性,从而让根存储池用任意特性。注意 GRUB 以只读方式打开存储池,因此所有兼容只读的特性都被 GRUB 支持。
提示:
如果创建镜像或 raidz 拓扑,可使用
zpool create ... bpool mirror /dev/disk/by-id/scsi-SATA_disk1-part3 /dev/disk/by-id/scsi-SATA_disk2-part3(或将mirror替换为raidz、raidz2或raidz3,并列出额外磁盘的分区)。可自定义存储池名称。如果更改,需在整个操作中保持一致。
bpool命名约定源自本教程。
2.4 创建根存储池:
选择以下其中任一方案:
2.4a 不加密:
2.4b LUKS 加密:
建议在此使用
ashift=12,因为如今许多硬盘的物理扇区为 4KiB(或更大),即使它们呈现为 512B 的逻辑扇区。未来更换的硬盘可能具有 4KiB 物理扇区(此时ashift=12是可选的)或 4KiB 逻辑扇区(此时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可显著提升扩展属性性能 performance of extended attributes。在 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 会重新分区,从而丢失引导加载器分区。对于 LUKS,选择的密钥大小为 512 位。但 XTS 模式需要两个密钥,因此 LUKS 密钥会被拆分为两半,
-s 512即表示 AES-256。密码可能是安全链中最薄弱的环节,请谨慎选择。参考 cryptsetup FAQ 第 5 节 获取指导。
提示:
如果创建镜像或 raidz 拓扑,可使用
zpool create ... rpool mirror /dev/disk/by-id/scsi-SATA_disk1-part4 /dev/disk/by-id/scsi-SATA_disk2-part4(或将mirror替换为raidz、raidz2或raidz3,并列出额外磁盘的分区)。对于 LUKS,使用/dev/mapper/luks1、/dev/mapper/luks2等,需要通过cryptsetup创建。存储池名称可自定义。如果要更改,需在所有操作中保持一致。在可自动安装到 ZFS 的系统上,根存储池默认命名为
rpool。
第三步:系统安装
3.1 创建作为容器的文件系统数据集:
在 Solaris 系统上,根文件系统会被克隆,并在通过 pkg image-update 或 beadm 进行重大系统变更时增加后缀。APT 虽可实现类似功能,但目前尚未实现。即使没有此类工具,仍可用于手动创建的克隆。
3.2 为根文件系统和引导文件系统创建文件系统数据集:
在 ZFS 中通常不需要使用挂载命令(mount 或 zfs mount),此处之所以需要,是因为设置了 canmount=noauto。
3.3 创建数据集:
以下数据集可选,取决于你的偏好,软件选择:
如果希望排除在快照之外:
如果系统使用 /opt:
如果系统使用 /srv:
如果系统使用 /usr/local:
如果系统将安装游戏:
如果系统将在 /var/mail 存储本地邮件:
如果系统将使用 Snap 软件包:
如果系统使用 /var/www:
如果系统将使用 GNOME:
如果系统将使用 Docker(管理自己的数据集和快照):
如果系统将使用 NFS(锁定):
建议之后使用 tmpfs,但如果希望为 /tmp 创建单独的数据集:
此数据集布局的主要目标是将操作系统与用户数据分离。这样可以在回滚根文件系统时,不影响用户数据,如 /var/log 中的日志。这在将来集成 beadm 或类似工具时尤为重要。com.sun:auto-snapshot 设置被一些 ZFS 快照工具用来排除临时数据。
如果不做额外操作,/tmp 将作为根文件系统的一部分存储。或者,你可以像上文示例那样为 /tmp 创建单独的数据集,这样 /tmp 数据不会包含在根文件系统的快照中。还可以对 rpool/tmp 设置配额,以限制最大使用空间。后续还可以使用 tmpfs(RAM 文件系统)。
3.4 安装最小系统:
debootstrap 命令会将新系统保持在未配置状态。替代方法是将既有可用系统的全部内容复制到新的 ZFS 根中。
第四步:系统配置
4.1 配置主机名(将 HOSTNAME 替换为所需主机名)。
提示: 如果觉得 vi 使用困难,可使用 nano。
4.2 配置网络接口:
如果系统不是 DHCP 客户端,请自定义此文件。
4.3 配置软件源:
4.4 将 LiveCD 环境的虚拟文件系统绑定到新系统并 chroot 进入:
注意: 使
用的是
--rbind,而不是--bind。
4.5 配置基本系统环境:
即使你需要非英语系统语言,也需确保 en_US.UTF-8 可用。
4.6 在新系统的 chroot 环境中安装 ZFS:
4.7 仅针对 LUKS 安装,配置 crypttab:
使用
initramfs是为了绕过 cryptsetup 不支持 ZFS 的问题。
提示:
如果创建镜像或 raidz 拓扑,请为
luks2等磁盘重复/etc/crypttab条目。
4.8 安装 GRUB
选择以下其中任一方案:
4.8a 安装 GRUB 用于传统(BIOS)启动
将 GRUB 安装到磁盘,而非分区。
4.8b 安装 GRUB 用于 UEFI 启动
mkdosfs中的-s 1仅对呈现 4 KiB 逻辑扇区(“4Kn”硬盘)的驱动器必要,以满足 FAT32 的最小簇大小(针对 512 MiB 分区),对呈现 512 B 扇区的驱动器也适用。
注意:
如果创建镜像或 raidz 拓扑,此步骤仅在第一块磁盘上安装 GRUB,其他磁盘稍后处理。
4.9 设置 root 密码
4.10 启用 bpool 导入
这可确保 bpool 始终被导入,无论在 /etc/zfs/zpool.cache 中是否存在、是否在缓存文件中,是否启用 zfs-import-scan.service。
4.11 可选(但推荐):将 tmpfs 挂载到 /tmp
如果之前创建了数据集 /tmp,则请跳过此步骤,因为两者冲突。否则,可以通过启用 tmp.mount 单元,将 /tmp 放在 tmpfs(RAM 文件系统)上。
4.12 可选(但推荐):安装 popcon
软件包 popularity-contest 会报告系统上安装的软件列表。显示 ZFS 的受欢迎程度有助于让 ZFS 获得发行版长期关注。
在出现提示时选择 Yes。
第五步:安装 GRUB
5.1 验证 ZFS 引导文件系统是否被识别:
5.2 更新 initrd 文件:
注意:
在使用 LUKS 时,可能会显示“WARNING could not determine root device from /etc/fstab”。这是因为 cryptsetup 不支持 ZFS。
5.3 解决 GRUB 对 ZFS 存储池特性支持缺失的问题:
5.4 可选(但强烈建议):便于调试 GRUB:
系统重启两次并确认一切正常后,可根据需要撤销这些更改。
5.5 更新引导配置:
注意:
如果出现报错
osprober,则可忽略。
5.6 安装引导加载器
5.6a 对于传统(BIOS)启动,将 GRUB 安装到 MBR:
在得到完全相同的结果信息前,请勿重启计算机。注意,此操作是将 GRUB 安装到整个磁盘,而非分区。
如果创建镜像或 raidz 拓扑,请对 pool 中的每块磁盘重复执行 grub-install 命令。
5.6b 对于 UEFI 启动,安装 GRUB:
5.7 验证 ZFS 模块安装情况:
5.8 修复文件系统挂载顺序
在 ZFS 支持 systemd 挂载生成器之前,文件系统挂载与某些守护进程启动之间存在竞争问题。实际上,问题(如 #5754)似乎出现在 /var 中的某些文件系统,特别是 /var/log 和 /var/tmp。将它们设置为使用 legacy 挂载,并在 /etc/fstab 中列出,使 systemd 知道它们是独立的挂载点。这样,rsyslog.service 通过 local-fs.target 依赖于 var-log.mount,使用 systemd PrivateTmp 特性的服务会自动依赖 After=var-tmp.mount。
现在,initramfs 尚未支持挂载 /boot,我们仍然需要手动挂载 /boot,因为它被标记为 canmount=noauto。此外,对于 UEFI,需要确保在其子文件系统 /boot/efi 挂载之前先挂载 /boot。
rpool 已由 initramfs 保证导入,因此不需要在这些文件系统上添加 x-systemd.requires=zfs-import.target。
第六步:首次启动
6.1 对初始安装进行快照:
将来,你可能希望在每次升级前创建快照,并在适当时候删除旧快照(包括此快照)以节省空间。
6.2 退出 chroot 环境回到 LiveCD 环境:
6.3 在 LiveCD 环境中运行以下命令卸载所有文件系统:
6.4 重启:
6.5 等待新安装的系统正常启动,使用 root 登录。
6.6 创建用户账户:
6.7 将用户账户添加到默认管理员组:
6.8 镜像 GRUB
如果安装到多块磁盘,请在其他磁盘上安装 GRUB:
6.8a 对于传统(BIOS)启动:
6.8b UEFI
第七步:(可选)配置交换空间
注意:
在内存压力极高的系统上,使用 zvol 作为交换设备可能导致系统锁死,无论交换空间还有多少可用。目前该问题正在调查中:https://github.com/zfsonlinux/zfs/issues/7734
7.1 创建用于交换的卷数据集(zvol):
可以根据需要调整大小(4G 部分)。
压缩算法设置为 zle,因为这是开销最小的算法。由于本指南推荐使用 ashift=12(磁盘上 4 KiB 块),对于常见的 4 KiB 页大小,没有压缩算法能降低 I/O。例外情况是全零页,ZFS 会丢弃它们;但必须启用某种压缩才能实现此行为。
7.2 配置交换设备:
注意:
在配置文件中始终使用长别名
/dev/zvol,绝不要使用短/dev/zdX设备名。
RESUME=none 用于禁用从休眠恢复。因为在恢复脚本运行时 zvol 尚未导入(未导入存储池),所以如果不禁用,启动过程会等待交换 zvol 出现而停滞 30 秒。
7.3 启用交换设备:
第八步:安装完整软件
8.1 升级最小系统:
8.2 安装常用软件集:
注意:
默认会勾选“Debian 桌面环境”和“打印服务器”。如果希望安装服务器版本,请取消勾选这些选项。
8.3 可选:禁用日志压缩:
由于 /var/log 已由 ZFS 压缩,logrotate 的压缩会消耗 CPU 和磁盘 I/O,但通常收益甚微。此外,如果你对 /var/log 进行快照,logrotate 的压缩反而会浪费空间,因为未压缩的数据仍然保留在快照中。你可以手动编辑 /etc/logrotate.d 中的文件注释掉 compress,或者使用以下循环(强烈建议复制粘贴):
8.4 重启:
第九步:最终清理
9.1 等待系统正常启动,使用你创建的账户登录。确保系统(包括网络)正常工作。
9.2 可选:删除初始安装快照:
9.3 可选:禁用 root 密码:
9.4 可选:重新启用图形化启动过程:
如果你希望使用图形化启动,现在可以重新启用。如果使用 LUKS,这会让提示界面更美观。
注意:
如果出现 osprober 错误,可忽略。
9.5 可选:仅针对 LUKS 安装,备份 LUKS 头:
将备份妥善保存(例如云存储)。备份受 LUKS 密码保护,但你也可以选择额外加密。
提示:如果你创建了镜像或 raidz 拓扑,请对每个 LUKS 卷重复此操作(luks2 等)。
故障排除
使用 Live CD 进行救援
请参考第一步:准备安装环境。
这将自动导入你的存储池。导出并重新导入以修正挂载:
如有需要,可以 chroot 进入已安装系统:
执行所需操作修复系统。
完成后,进行清理:
MPT2SAS
本教程的大多数问题报告都与硬件 mpt2sas 相关,这类硬件会进行缓慢的异步磁盘初始化,例如一些 IBM M1015 或刷成参考 LSI 固件的 OEM 卡。
基本问题是,这些控制器上的磁盘在 Linux 内核启动常规系统之前不可见,而 ZoL 不支持热插拔存储池成员。详见 https://github.com/zfsonlinux/zfs/issues/330。
大多数 LSI 卡与 ZoL 完全兼容。如果你的卡存在此问题,尝试在 /etc/default/zfs 中设置 ZFS_INITRD_PRE_MOUNTROOT_SLEEP=X。系统将在导入存储池前等待 X 秒以确保所有磁盘被识别。
Areca
需要 arcsas 驱动的系统,应将 arcsas 添加到文件 /etc/initramfs-tools/modules 中,并运行 update-initramfs -u -k all。
如果内核日志中出现类似 RIP: 0010:[<ffffffff8101b316>] [<ffffffff8101b316>] native_read_tsc+0x6/0x20 的信息,请升级或降级 Areca 驱动。在出现此错误信息的设备上使用 ZoL 并不稳定。
VMware
在 vmx 文件或 vsphere 配置中设置
disk.EnableUUID = "TRUE"。此操作确保在虚拟机中创建/dev/disk别名。
QEMU/KVM/XEN
使用 libvirt 或 qemu 为每个虚拟磁盘设置唯一序列号(例如 -drive if=none,id=disk1,file=disk1.qcow2,serial=1234567890)。
要在虚拟机中使用 UEFI(而不仅仅是 BIOS 启动),在宿主机上执行:
最后更新于