github编辑

构建以 ZFS 为根文件系统的 Debian 9 (Stretch)

概述

有更新版本

注意事项

  • 本教程将使用整块物理磁盘。

  • 本教程不适用于双系统环境。

  • 请先备份数据。现有数据都将被清除。

系统要求

内存小于 2 GiB 的计算机运行 ZFS 时会非常缓慢。在基础工作负载下,建议至少 4 GiB 内存,才能获得正常性能。如果你希望使用去重(deduplication),则需要大量内存arrow-up-right。启用去重是不可逆的永久性更改,无法轻易恢复。

加密

本指南支持两种加密方案:未加密和 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;否则请参考故障排查arrow-up-right部分。

  • 如果你要创建镜像或 raidz 拓扑,请对 pool 中的所有磁盘重复分区命令。

2.3 创建引导存储池:

通常无需为引导存储池自定义任何选项。

GRUB 并不支持所有 ZFS 存储池特性。参见 grub-core/fs/zfs/zfs.carrow-up-right 中的 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 替换为 raidzraidz2raidz3,并列出额外磁盘的分区)。

  • 可自定义存储池名称。如果更改,需在整个操作中保持一致。bpool 命名约定源自本教程。

2.4 创建根存储池:

选择以下其中任一方案:

2.4a 不加密:

2.4b LUKS 加密:

  • 建议在此使用 ashift=12,因为如今许多硬盘的物理扇区为 4KiB(或更大),即使它们呈现为 512B 的逻辑扇区。未来更换的硬盘可能具有 4KiB 物理扇区(此时 ashift=12 是可选的)或 4KiB 逻辑扇区(此时 ashift=12 是必需的)。

  • 设置 -O acltype=posixacl 可全局启用 POSIX ACL。如果不需要,可移除此选项,但之后在创建 /var/logzfs create 时需添加 -o acltype=posixacl(注意小写“o”),因为 journald 需要 ACLarrow-up-right

  • 设置 normalization=formD 可消除一些与 UTF-8 文件名规范化相关的极端情况,同时隐含 utf8only=on,意味着只允许 UTF-8 文件名。如果希望支持非 UTF-8 文件名,请勿使用此选项。关于强制 UTF-8 文件名可能带来的问题,请参见 The problems with enforced UTF-8 only filenamesarrow-up-right

  • 设置 relatime=on 是经典 POSIX atime 行为(性能影响较大)和 atime=off(完全禁用 atime 更新来获得最佳性能)之间的折中。自 Linux 2.6.30 起,其他文件系统默认启用 relatime。详情请参见 RedHat 文档arrow-up-right

  • 设置 xattr=sa 可显著提升扩展属性性能 performance of extended attributesarrow-up-right。在 ZFS 内部,扩展属性用于实现 POSIX ACL,也可被用户空间应用使用。部分桌面 GUI 应用使用扩展属性arrow-up-rightSamba 可利用扩展属性存储 Windows ACL 和 DOS 属性;Samba Active Directory 域控制器也需要它们arrow-up-right。请注意,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 节arrow-up-right 获取指导。

提示:

  • 如果创建镜像或 raidz 拓扑,可使用 zpool create ... rpool mirror /dev/disk/by-id/scsi-SATA_disk1-part4 /dev/disk/by-id/scsi-SATA_disk2-part4(或将 mirror 替换为 raidzraidz2raidz3,并列出额外磁盘的分区)。对于 LUKS,使用 /dev/mapper/luks1/dev/mapper/luks2 等,需要通过 cryptsetup 创建。

  • 存储池名称可自定义。如果要更改,需在所有操作中保持一致。在可自动安装到 ZFS 的系统上,根存储池默认命名为 rpool

第三步:系统安装

3.1 创建作为容器的文件系统数据集:

在 Solaris 系统上,根文件系统会被克隆,并在通过 pkg image-updatebeadm 进行重大系统变更时增加后缀。APT 虽可实现类似功能,但目前尚未实现。即使没有此类工具,仍可用于手动创建的克隆。

3.2 为根文件系统和引导文件系统创建文件系统数据集:

在 ZFS 中通常不需要使用挂载命令(mountzfs 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:

提示:

如果创建镜像或 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 不支持 ZFSarrow-up-right

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 挂载生成器之前arrow-up-right,文件系统挂载与某些守护进程启动之间存在竞争问题。实际上,问题(如 #5754arrow-up-right)似乎出现在 /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/7734arrow-up-right

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 进行救援

请参考第一步:准备安装环境arrow-up-right

这将自动导入你的存储池。导出并重新导入以修正挂载:

如有需要,可以 chroot 进入已安装系统:

执行所需操作修复系统。

完成后,进行清理:

MPT2SAS

本教程的大多数问题报告都与硬件 mpt2sas 相关,这类硬件会进行缓慢的异步磁盘初始化,例如一些 IBM M1015 或刷成参考 LSI 固件的 OEM 卡。

基本问题是,这些控制器上的磁盘在 Linux 内核启动常规系统之前不可见,而 ZoL 不支持热插拔存储池成员。详见 https://github.com/zfsonlinux/zfs/issues/330arrow-up-right

大多数 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 启动),在宿主机上执行:

最后更新于