配置ZFS自动启动

在完成 Docker ZFS 存储驱动 配置并使用之后,如果重启物理主机,你会惊讶地发现 docker.service 启动失败,原因是 /var/lib/docker 没有就绪。

手工启动zfs

此时检查ZFS会发现 zpool 是空的:

zpool list/ zfs list 都输出空
# zpool list
no pools available
zfs list
no datasets available
  • 检查 zpool import 可以看到存储池是就绪的(但是没有导入):

zpool import可以看到zpool-docker就绪但没有导入
# zpool import
   pool: zpool-docker
     id: 4553342928876801142
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        zpool-docker  ONLINE
          nvme0n1p9   ONLINE
  • 手工导入:

zpool import zpool-docker
zpool import zpool-docker

此时再次检查就能够看到zfs文件系统已经挂载 ( df -h ):

Filesystem      Size  Used Avail Use% Mounted on
...
zpool-docker    102G  6.4G   95G   7% /var/lib/docker

并且 zfs list 可以看到所有该存储池下文件系统:

NAME                                                                                 USED  AVAIL     REFER  MOUNTPOINT
zpool-docker                                                                        8.04G  94.7G     6.34G  /var/lib/docker
zpool-docker/03ebbb6554f2f15ee36cedacade890f080081631375a60e3796fd160e6788a6d        104K  94.7G     16.6M  legacy
zpool-docker/09315a96dcbfbfbc33929960905fc09793bd731a7645cdc625d56079d1643545        112K  94.7G     16.6M  legacy
...

配置自动导入和启动ZFS

ZFS被其创建者视为”零管理”文件系统,所以配置ZFS非常简单,主要使用 zfszpool 命令

自动启动

为了实现ZFS的”零管理”:

  • 必须启用 zfs-import-cache.service 以导入存储池(import pools): zfs-import-cache.service 是通过 /etc/zfs/zpool.cache 配置来导入ZFS存储池

  • 必须启用 zfs-mount.service 以挂载存储池中可用的文件系统(这样就不需要使用 /etc/fstab 来挂载ZFS)

对于每个想要 自动 通过 zfs-import-cache.service 自动实现自动导入的存储池,可以执行如下命令:

zpool set cachefile=/etc/zfs/zpool.cache <pool>

备注

从 OpenZFS 0.6.5.8 版本开始,必须明确激活ZFS服务

除了 zfs-mount.service 以外,也可以使用 zfs-mount-generator 来完成 zfs-import-cache.service 之后的zfs挂载,区别在于 zfs-mount.service 不能保证 /var 目录足够提前完成挂载,此时就需要使用 zfs-mount-generator 来替代实现

方法一: zfs-import-cache + zfs-mount

  • 激活 zfs-import-cache + zfs-mount :

激活 zfs-import-cache 和 zfs-mount 确保启动时自动挂载ZFS
sudo systemctl enable zfs-import-cache.service
sudo systemctl enable zfs-mount.service

备注

升级 Arch Linux 系统可能启动时日志显示报错:

[    0.879506 ] systemd[306]: /usr/lib/systemd/system-generators/zfs-mount-generator failed with exit status 127.

启动后执行 zpool import 报错:

zpool: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory

原因是系统默认安装最新版本的 openssl 3.0.7-2 ,自动卸载了不需要的 openssl-1.1 1.1.1.s-2 ,但是第三方安装需要这个库,所以单独安装:

pacman -S openssl-1.1

这样就不会再出现 zpool import 报lib库文件问题,启动日志也就不报错了。为避免后续升级 openssl-1.1 被自动清理,采用 Pacman 的版本hold配置,也就是修订 /etc/pacman.conf 添加:

IgnorePkg   = openssl-1.1

不过,对于 /var 目录及其下子目录,挂载还是需要采用 zfs-mount-generator

方法二: zfs-import-cache + zfs-mount-generator

对于 Docker ZFS 存储驱动 ,ZFS存储池是位于 /var/lib/docker ,也就是 /var 子目录。如果采用上文 zfs-import-cache + zfs-mount 会发现启动还是没有自动挂载。

原因是 /var 目录需要在系统启动早期时挂载,此时 zfs 内核模块尚未加载。这就导致 zpool-docker 这个 zpool 导入失败。

对于上述问题,需要改为使用 zfs-mount-generator 替代 zfs-mount.service 来确保启动时创建好 systemd mount units ,这样 Systemd进程管理器 就会自动基于 mount units 完成文件系统挂载而无需使用 zfs-mount.service :

  • 创建 /etc/zfs/zfs-list.cache 目录:

    mkdir /etc/zfs/zfs-list.cache
    
  • 激活 ZFS Event Daemon(ZED) 脚本(称为 ZEDLET) 请求来创建一系列ZFS文件系统挂载列表(对于OpenZFS>=2.0.0这个链接是自动创建的):

    ln -s /usr/lib/zfs/zed.d/history_event-zfs-list-cacher.sh /etc/zfs/zed.d
    
  • 激活 zfs.targetzfs-zed.service 并启动 zfs-zed.service

    systemctl enable zfs-import-cache
    systemctl disable zfs-mount
    
    systemctl enable zfs.target
    systemctl enable zfs-zed.service
    systemctl start zfs-zed.service
    
  • /etc/zfs/zfs-lilst.cache 目录下创建存储池命名的空文件:

    touch /etc/zfs/zfs-list.cache/<pool-name>
    
  • 检查 /etc/zfs/zfs-list.cache/<pool-name> 内容,如果这个文件是空的,则确保 zfs-zed.service 正在运行情况下,然后通过以下命令修改ZFS文件系统的 canmount 属性:

    zfs set canmount=off zroot/fs1
    

这个命令会导致ZFS的事件被ZED捕获,此时就会运行ZEDLET来更新 /etc/zfs/zfs-list.cache 目录下文件内容。如果此时检查了 /etc/zfs/zfs-list.cache/<pool-name> 有内容之后,再将文件系统重新设置 canmount 属性:

zfs set canmount=on zroot/fs1

备注

我这里没有采用设置 zpool/zpool-dockercanmount 属性开关,是因为我这时刚重启主机, zpool-docker 尚未自动导入。所以我采用了命令 zpool import zpool-docker 命令,也同样可以触发 ZED 自动更新 /etc/zfs/zfs-list.cache/zpool-docker 内容。anyway,只要有ZED事件发生就能触发更新。

  • 完整的针对 zpool-docker zpool存储池的操作命令如下:

使用zfs-mount-generator自动启动ZFS
mkdir /etc/zfs/zfs-list.cache

systemctl enable zfs-import-cache
systemctl disable zfs-mount

systemctl enable zfs.target
systemctl enable zfs-zed.service
systemctl start zfs-zed.service

touch /etc/zfs/zfs-list.cache/zpool-docker

# 触发 /etc/zfs/zfs-list.cache/zpool-docker 更新
zfs set canmount=off zpool/zpool-docker
zfs set canmount=on zpool/zpool-docker

然后重新启动操作系统观察 /var/lib/docker 就是正常自动挂载的:

Filesystem      Size  Used Avail Use% Mounted on
...
zpool-docker    102G  6.8G   95G   7% /var/lib/docker

couldn't start libzfs

我在完成 zfs-import-cache + zfs-mount-generator 配置之后,确实启动之后自动导入 zpool/zpool-docker 并挂载好 /var/lib/docker ,但是我发现 dmesg -T 依然有一个ZFS相关报错:

[Mon Nov 21 15:21:34 2022] zfs-mount-generator[322]: couldn't start libzfs, ignoring
[Mon Nov 21 15:21:35 2022] ZFS: Loaded module v2.1.6-1, ZFS pool version 5000, ZFS filesystem version 5

暂时没有发现 zpoolzfs 问题,待查

参考