Gentoo上运行ZFS

安装

ZFSOnLinux项目 提供了out-of-tree Linux内核模块。从ZFS模块版本 0.6.1 开始,OpenZFS项目宣布将ZFS视为可以广泛用于桌面到超级计算机的生产部署。

  • 安装ZFS:

emerge 安装 zfs
emerge --ask sys-fs/zfs

安装完成后提示信息:

emerge 安装 zfs 后提示信息
 * Messages for package sys-fs/zfs-kmod-2.2.2:

 * You have virtual/dist-kernel installed, but
 * USE="dist-kernel" is not enabled for sys-fs/zfs-kmod
 * It's recommended to globally enable dist-kernel USE flag
 * to auto-trigger initrd rebuilds with kernel updates

 * Messages for package sys-fs/zfs-2.2.2-r1:

 * You have virtual/dist-kernel installed, but
 * USE="dist-kernel" is not enabled for sys-fs/zfs
 * It's recommended to globally enable dist-kernel USE flag
 * to auto-trigger initrd rebuilds with kernel updates

 * Messages for package sys-fs/zfs-kmod-2.2.2:

 * This version of OpenZFS includes support for new feature flags
 * that are incompatible with previous versions. GRUB2 support for
 * /boot with the new feature flags is not yet available.
 * Do *NOT* upgrade root pools to use the new feature flags.
 * Any new pools will be created with the new feature flags by default
 * and will not be compatible with older versions of OpenZFS. To
 * create a new pool that is backward compatible wih GRUB2, use 
 * 
 * zpool create -o compatibility=grub2 ...
 * 
 * Refer to /usr/share/zfs/compatibility.d/grub2 for list of features

警告

每次内核编译之后,都需要重新 emerge sys-fs/zfs-kmod ,即使内核修改是微不足道的。如果你在merge了内核模块之后重新编译内核,则可能会是的zpool进入不可中断的睡眠(也就是不能杀死的进程)或者直接crash。

  • 在内核变更之后,执行以下命令重新 remerge zfs-kmod :

重新emerge zfs-kmod
emerge -va @module-rebuild

输出信息类似:

重新emerge zfs-kmod
...
Calculating dependencies... done!
Dependency resolution took 1.73 s (backtrack: 0/20).

[ebuild   R    ] sys-fs/zfs-kmod-2.1.14:0/2.1.14::gentoo  USE="dist-kernel-cap rootfs strip -custom-cflags -debug -dist-kernel -modules-sign -verify-sig" 0 KiB

Total: 1 package (1 reinstall), Size of downloads: 0 KiB

Would you like to merge these packages? [Yes/No]

ZFS Event Daemon通知

ZED(ZFS Event Daemon)监控ZFS内核模块产生的事件: 当一个 zevent (ZFS Event)发出是,ZED将为对应的zevent分类运行一个 ZEDLETs (ZFS Event Daemon Linkage for Executable Tasks)。

  • 配置 /etc/zfs/zed.d/zed.rc :

/etc/zfs/zed.d/zed.rc 配置案例,激活通知邮件地址以及定期发送pool健康通知
##
# Email address of the zpool administrator for receipt of notifications;
#   multiple addresses can be specified if they are delimited by whitespace.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
# Enabled by default; comment to disable.
#
ZED_EMAIL_ADDR="admin@example.com"

##
# Notification verbosity.
#   If set to 0, suppress notification if the pool is healthy.
#   If set to 1, send notification regardless of pool health.
#
ZED_NOTIFY_VERBOSE=1

OpenRC

  • 配置 openrc 设置ZFS在操作系统启动时启动:

配置 openrc 设置ZFS服务
# 多数情况下只需要配置 zfs-import 和 zfs-mount
rc-update add zfs-import boot
rc-update add zfs-mount boot

# zfs-share 是提供NFS共享
rc-update add zfs-share default
# zfs-zed 是ZFS Event Daemon用于处理磁盘hotspares替换以及故障的电子邮件通知
rc-update add zfs-zed default

备注

  • 多数情况下只需要配置 zfs-import 和 zfs-mount

  • zfs-share 是提供NFS共享

  • zfs-zed 是ZFS Event Daemon用于处理磁盘hotspares替换以及故障的电子邮件通知

Systemd

如果系统使用 Systemd进程管理器 则配置如下:

配置 systemd 设置ZFS服务
systemctl enable zfs.target
systemctl start zfs.target

systemctl enable zfs-import-cache
systemctl enable zfs-mount
systemctl enable zfs-import.target

内核

sys-fs/zfs 需要内核支持 zlib :

sys-fs/zfs 需要内核支持 zlib
Cryptographic API --->
  Compression --->
    <*> Deflate

备注

内核更改必须重新编译内核模块

如果使用clang来编译 sys-fs/zfs-kmod 则必须使用 2.1.7 以上版本

安装内核模块(前面安装 zfs 已经包括):

安装 zfs-kmod
emerge --ask sys-fs/zfs-kmod

如果使用 initramfs ,则需要在编译模块以后重新生成initramfs

  • 如果服务器没有重启过,可能需要手工夹在 zfs 内核模块:

手工加载zfs模块
/sbin/modprobe zfs

使用

  • 磁盘分区:

这里的案例是 在MacBook Pro上安装Gentoo Linux ,磁盘已经划分了 sda1 (/boot) 和 sda2 (/) ,现在将剩余空间都作为ZFS分区:

使用 parted分区工具 创建 /dev/sda3 分区用于ZFS
# 已经划分了 sda1 和 sda2 ,用掉了21G,所以这里从 21GB开始到100%
parted -a optimal /dev/sda mkpart primary 21GB 100%

# 为磁盘分区3命名
parted /dev/sda name 3 zpool-data

# 最后显示输出磁盘分区信息
parted /dev/sda print

划分好以后,最后输出的分区信息:

使用 parted分区工具 创建 /dev/sda3 分区用于ZFS
Model: ATA APPLE SSD SD0128 (scsi)
Disk /dev/sda: 121GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name        Flags
 1      1049kB  256MB   255MB   fat32        ESP         boot, esp
 2      256MB   21.0GB  20.7GB  xfs          rootfs
 3      21.0GB  121GB   100GB                zpool-data
  • ( 仅供参考 请不要执行这步 )如果是常规使用,通常可以使用类似 ZFS快速起步(zcloud) 方法(注意那个案例使用的是整块sda磁盘,和这里的案例磁盘分区 /dev/sda3 不同,注意区别):

在磁盘 sda 上创建ZFS的存储池,名字为 zpool-data
zpool create zpool-data sda
# 设置了从zpool的根开始激活压缩
zfs set compression=lz4 zpool-data
创建 Docker ZFS 存储驱动 存储池
# 在 /dev/sda3 分区创建zpool
sudo zpool create -f zpool-docker -m /var/lib/docker /dev/sda3

# 存储池开启压缩,2015年后openzfs默认压缩算法LZ4,这里明确设置lz4
sudo zfs set compression=lz4 zpool-docker

完成以后检查 zpool list 可以看到新创建的 zpool-docker 存储池:

zpool list 输出显示新创建的 zpool-docker 存储池
NAME           SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zpool-docker    93G   588K  93.0G        -         -     0%     0%  1.00x    ONLINE  -

再检查 zfs list 可以看到这个存储池 zpool-docker 被挂载到 /var/lib/docker (通过 df -h 也能看到):

zfs list 输出显示 存储池 zpool-docker 被挂载到 /var/lib/docker
NAME           USED  AVAIL     REFER  MOUNTPOINT
zpool-docker   492K  90.1G       96K  /var/lib/docker

一切就绪,现在可以执行 Gentoo Docker 部署了

子卷配置

我的 MacBook Air 13” Mid 2013 内置存储空间有限(128G),所以我在 在MacBook Pro上安装Gentoo Linux ( MacBook Air 13” Mid 2013 ),为操作系统分配了很小的分区(20G):

分配给 rootfs/dev/sda2 只有20G
Model: ATA APPLE SSD SD0128 (scsi)
Disk /dev/sda: 121GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name        Flags
 1      1049kB  256MB   255MB   fat32        ESP         boot, esp
 2      256MB   21.0GB  20.7GB  xfs          rootfs
 3      21.0GB  121GB   100GB                zpool-data

虽然 rootfs 精简能够空出更多宝贵的磁盘空间给数据盘,但是Gentoo的编译需要很大的空间,特别是 Gentoo内核编译 。所以我在上文的 zpool-docker 存储池中划分出一些子卷给特定的数据目录 – 通过 排查磁盘空间消耗 找到最消耗空间目录:

/var/cache
/var/tmp
/usr/src

Gentoo 虚拟化 libvirt

/var/lib/libvirt
  • 将需要迁移的目录先重命名(添加 .bak 后缀),然后创建对应的 ZFS 子卷 指定 ZFS挂载 到对应目录下,最后使用 tar 命令迁移数据,并清理掉无用数据释放空间:

将系统中占用空间较大的目录迁移到 ZFS 子卷
# 重命名需要迁移的数据目录
mv /var/cache /var/cache.bak
mv /var/tmp /var/tmp.bak
mv /usr/src /usr/src.bak
mv /var/lib/libvirt /var/lib/libvirt.bak

# 创建ZFS存储卷的子卷,挂载到相应目录
zfs create -o mountpoint=/var/cache zpool-docker/var-cache
zfs create -o mountpoint=/var/tmp zpool-docker/var-tmp
zfs create -o mountpoint=/usr/src zpool-docker/usr-src
zfs create -o mountpoint=/var/lib/libvirt zpool-docker/var-lib-libvirt

# 数据迁移
(cd /var/cache.bak && tar cf - .)|(cd /var/cache && tar xf -)
(cd /var/tmp.bak && tar cf - .)|(cd /var/tmp && tar xf -)
(cd /usr/src.bak && tar cf - .)|(cd /usr/src && tar xf -)
(cd /var/lib/libvirt.bak && tar cf - .)|(cd /var/lib/libvirt && tar xf -)

# 清理无用数据
rm -rf /var/cache.bak
rm -rf /var/tmp.bak
rm -rf /usr/src.bak
rm -rf /var/lib/libivrt.bak

参考