Linux 更换根目录的 FS 为 ZFS 是可行的,写一篇教程记录下大致步骤和可能出现的问题

准备

  • 不比系统盘小的一块空硬盘

操作过程

1 - ZFS 驱动和工具

Debian 目前默认的内核并没有集成 ZFS 驱动,必须更换内核或者手动安装内核模块才能正常使用 ZFS

方法一

这里可以直接安装 proxmox-ve 包,Proxmox VE 自带了 ZFS 的管理工具和驱动(驱动由 Proxmox VE 的定制内核提供), 且 PVE 对 ZFS 的支持也非常全:

如果你安装了 qemu,此方法会将你的 qemu 替换为 PVE 修改后的版本

如果你使用 systemd-timesyncd 用于时间同步,此方法会将你的 systemd-timesyncd 替换为 chrony

下面的安装命令仅适用于 Debian 12 Bookworm AMD64,其他 Debian 版本或其他架构无法使用

1
2
3
4
5
6
7
echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list
wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg
apt update
apt install proxmox-default-kernel proxmox-ve postfix open-iscsi chrony -y
apt remove linux-image-amd64 'linux-image-6.1*' -y
update-grub
systemctl reboot

如果只使用 Proxmox VE 的 ZFS 管理工具和驱动,不使用 Proxmox VE 虚拟机,可以考虑把 proxmox-ve 卸载掉:apt remove proxmox-ve -y

方法二

使用原有内核,不安装 proxmox-ve 或其他内核,使用 dkms 手动安装 ZFS 驱动

此方法可能无法在启用了 UEFI 安全启动的设备上正常工作,原因如下:

Linux 5.4 中添加了 kernel_lockdown 功能,在启用 UEFI 安全启动的设备上,kernel_lockdown 强制启用,此功能只能在内核编译时去掉

kernel_lockdown 会阻止系统载入未签名的自定义模块,zfs-dkms 就是未签名的模块

您必须为内核和 dkms 配置自定义签名才能在启用了 UEFI 安全启动的设备上使用此方法(流程非常复杂,可能还需要在 UEFI 固件设置里手动导入证书,能单独再写一篇文章了)

1
2
apt install linux-headers-amd64 zfsutils-linux zfs-dkms
modprobe zfs

2 - 复制磁盘数据

假设原硬盘的分区结构如下:

vda
123
BIOS BootLinux filesystemLinux LVM
ext4 /bootVG system
rootswap
btrfs /swap

先把系统盘(以 vda 为例)复制到另一块盘 vdb,然后清除掉 vdb 上的 boot 和 root 分区

如果你的系统盘上有 LVM,你需要在磁盘克隆后使用 vgimportclone 重新生成 LVM 的 UUID,命令已在下方给出

UEFI 用户需要两个分区用于启动,一个是 ESP(应挂载到 /boot/efi),另一个是 ZFS 启动分区(应挂载到 /boot),我只以传统引导演示,因为我不使用 UEFI 也没有 ESP(

1
2
3
4
5
vgrename system systemOld
dd if=/dev/vda of=/dev/vdb bs=1M status=progress
vgimportclone /dev/vdb3 -n system # regen LVM uuids
wipefs -a /dev/vdb2
wipefs -a /dev/system/root

完成后磁盘分区结构大致是:

vdb
123
BIOS BootLinux filesystemLinux LVM
VG system
rootswap
swap

3 - 创建 ZFS

bpool,用于引导:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
zpool create \
-f \
-o cachefile= \
-o ashift=12 -d \
-o feature@async_destroy=enabled \
-o feature@bookmarks=enabled \
-o feature@embedded_data=enabled \
-o feature@empty_bpobj=enabled \
-o feature@enabled_txg=enabled \
-o feature@extensible_dataset=enabled \
-o feature@filesystem_limits=enabled \
-o feature@hole_birth=enabled \
-o feature@large_blocks=enabled \
-o feature@livelist=enabled \
-o feature@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@zpool_checkpoint=enabled \
-O acltype=posixacl -O canmount=off -O compression=lz4 \
-O devices=off -O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/boot -R /mnt \
bpool \
/dev/vdb2

rpool,存储 rootfs:

1
2
3
4
5
6
7
8
zpool create \
-f \
-o ashift=12 \
-O acltype=posixacl -O canmount=off -O compression=lz4 \
-O normalization=formD -O relatime=on \
-O xattr=sa -O mountpoint=/ -R /mnt \
rpool \
/dev/system/root

创建数据集:

1
2
3
zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/proxmox
zfs mount rpool/ROOT/proxmox
zfs create -o mountpoint=/boot bpool/BOOT/proxmox

上面的操作完成后磁盘分区结构大致是:

vdb
123
BIOS BootLinux filesystemLinux LVM
zpool bpoolVG system
BOOTzpool rpoolswap
zfs /bootROOTswap
zfs /

4 - 拷贝文件

1
2
3
apt install rsync -y
rsync -axHAWXS --numeric-ids --info=progress2 / /mnt
rsync -axHAWXS --numeric-ids --info=progress2 /boot /mnt

5 - 更新引导

在 vdb 创建新的引导文件:

1
2
3
4
5
6
7
8
mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --rbind /dev /mnt/dev
chroot /mnt
apt install zfs-initramfs -y
update-initramfs -c -k all
grub-install /dev/vdb
update-grub

6 - 更新 fstab

ZFS 不依赖 fstab 挂载,挂载信息存储在文件系统中,自行清理 fstab 的无用条目

7 - 导出 ZFS

1
2
3
4
exit # quit chroot
mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | \
xargs -i{} umount -lf {}
zpool export -a

8 - 将 ZFS 写回原系统盘

方法一

如果有 LiveCD,直接进 LiveCD 执行:

1
dd if=/dev/vdb of=/dev/vda status=progress

方法二

如果没有 LiveCD,则将根目录系统挂载为只读,然后再复制:

1
2
3
mount -o remount,ro / # soft remount ro
echo u > /proc/sysrq-trigger # force remount ro, not work in btrfs
dd if=/dev/vdb of=/dev/vda status=progress

9 - 启动新的系统

卸载原有硬盘,重启即可,最终效果如下

ZFS installed

可能出现的问题

A - initramfs 无法加载 ZFS 驱动

  • 症状:出现 Failed to load the ZFS Module. 提示
  • 原因:未正确对模块进行签名,UEFI 安全启动策略不允许载入

B - initramfs 未找到 zpool

  • 症状:开机时卡在 Begin: Running /scripts/local-block … done 很久
  • 症状:出现 ZFS Boot failing in initramfs : Alert! ZFS=rpool/ROOT/proxmox does not exists 类似提示
  • 原因:initramfs 中没有 zfs 工具,或 zpool 无法被安全导入,请确认第 5 步的 zfs-initramfs 是否正确安装、第 7 步是否成功导出
  • 解决方案:尝试运行 zpool import -f bpool rpool && exit,如果出现 command not found,说明 zfs-initramfs 未正确安装,请重新执行全部步骤

C - ZFS 根目录无法卸载

  • 症状:完成第 7 步时出现 cannot unmount '/mnt': pool or dataset is busy
  • 原因:第 3 步完成后,ZFS 所在的磁盘路径发生变化,或者有其他程序占用
  • 解决方法:如果更改了磁盘路径,需要先修改回来,然后检查是否有程序占用,如果有,请关闭,完成后重新尝试第 7 步,若仍然失败,请重启系统

参考资料