基于 ZFS 根分区安装 ArchLinux 以及配置 ZFSBootMenu 引导

发布于 2024-04-24  251 次阅读


0x00 前言

  • ZFS是一款十分强大的文件系统,ZFS 的特点包括:存储池(被称为 "zpool" 的集成卷管理系统)、写时复制、快照、数据完整性校验和自动修复(擦除)、RAID-Z、最大 16 EB 文件大小,以及最大 256×10¹⁵ ZB 存储,且对文件系统(数据集)或文件的数量没有限制,ZFS 采用 Community Development and Distribution License(CDDL)授权。
  • ZFS 被称为 "终极文件系统",稳定、快速、安全、面向未来。但是由于采用 CDDL 许可证,因此与 GPL 不兼容,ZFS 不可能与 Linux 内核一起发布。然而,这并不妨碍第三方开发者开发并发布原生的 Linux 内核模块,比如 OpenZFS (以前被称为 ZFS on Linux [ZOL])。也因为ZFS的许可证原因,ArchLinux官方发布的ISO安装介质并没有直接提供ZFS支持.
  • 本文详细介绍基于ZFS根文件系统的 ArchLinux 发行版安装

0x01 准备一个支持 ZFS 的 ISO 安装介质

 
这里我提供两个方案,选择其中之一即可。
 

1.使用 arch-iso-zfs (推荐)

直接运行官方ISO安装介质,在启动完成后运行使用 arch-iso-zfs 脚本即可。

> curl -s https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init|bash

 

2.使用 archiso 构建支持 ZFS 的自定义 ISO 安装介质

 
构建镜像首先需要一个 ArchLinux 系统,可以使用容器来进行构建,手里有啥就用啥。
 

2.1.安装 archiso 包并创建一个文件夹以存放必要的配置文件
>pacman -Sy archiso
>mkdir archiso
>cp -r /usr/share/archiso/configs/releng/* ./archiso

 

2.2.添加 archzfs 源并将 ZFS 相关依赖写入配置文件
>echo -e "[archzfs]nServer = https://archzfs.com/$repo/$arch" >> /etc/pacman.conf
>echo -e "linux-headersnzfs-dkmsnzfs-utils"

 
备注:archzfs源目前并没有国内镜像,官方源在国内不一定能稳定连接,如果出现网络问题请自行换源或者使用稳定的网络进行创建,其他镜像源请参见 archzfs wiki
 

2.3.开始创建带 ZFS 支持的 Arch Linux ISO 安装介质
# 运行后耐心等待一段时间即可在 archiso_out 文件夹取得自定义ISO安装介质
# 文件名一般为archlinux-[日期]-x86_64.iso
>mkarchiso -vo archiso_out ./archiso

0x02 启动 ISO 安装介质,创建基础磁盘分区

 

1.将你的 ISO 安装介质用你喜欢的方法写入U盘,默认设置启动第一个启动项即可进入 CLI

进入CLI后运行 arch-iso-zfs 脚本加载 ZFS 模块(如果你使用的是在第一节第二种方法创建的支持ZFS的自定义ISO安装介质可跳过这步)
 

2.创建基础磁盘分区

在使用 UEFI+GPT 的引导模式下使用ZFS作为根文件系统安装系统只需要硬盘存在两个区块,第一个区块为 EFI 引导分区(建议设置200M 以上),第二个区块作为 ZFS 池分区,可以使用 cfdisk 命令来将硬盘分区表设置为 GPT,以及预先建立区块和设置分区类型,硬盘基础区块设置完成后使用 mkfs.vfat 来格式化引导分区,以上操作完成后使用 lsblk 命令查看区块分布看起来类似这样:
 

>lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda      8:0    0 238.5G  0 disk
├─sda1   8:1    0     1G  0 part
└─sda2   8:2    0 237.5G  0 part

 
使用以下命令可以查看当前的启动方式,如果你的启动方式不是 UEFI,请重新设置主板启动方式为 UEFI 再进行安装。

>[ -d /sys/firmware/efi ] && echo UEFI||echo BIOS

0x03 添加软件源,创建 ZFS 储存池

1.添加 archzfs(必须)archlinuxcn(可选) 源,以及更改主存储库源为国内镜像。

 

# 添加软件源
>echo -e "[archzfs]nServer = https://archzfs.com/$repo/$arch" >> /etc/pacman.conf
>echo -e "[archlinuxcn]nServer = https://mirrors.ustc.edu.cn/archlinuxcn/$arch" >> /etc/pacman.conf
>echo -e "Server = https://mirrors.ustc.edu.cn/$repo/$arch" > /etc/pacman.d/mirrorlist
 
# 更新软件源密钥
>pacman-key --lsign-key "[email protected]"
>pacman-key -r DDF7DB817396A49B2A2723F7403BD972F75D9D76
>pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
 
# 安装密钥库
pacman -Sy archlinuxcn-keyring

 

2.创建 ZFS 池,以下参数来自 Arch Linux WiKi,挑重点解释下作用,如果没有特殊需求按照默认参数即可。

  • ashift=12:其中12代表4096扇区大小,9代表512扇区大小,13代表8192扇区大小,尽量让该参数对应到磁盘物理扇区大小,在4096/8192扇区的磁盘上设置9会导致性能损失,在512扇区的磁盘上设置12/13会导致容量损失,硬盘扇区大小请自行通过工具或查询厂商 datasheet 获取,实在不知道请保持默认设置即可。
  • dedup=on:开启去重功能,该功能会占用大量 RAM,主机性能不足的慎重选择。
  • compression=zstd:启用 zstd 透明压缩算法,该算法性能和压缩率比较平衡,在意性能可以关闭压缩,不推荐使用 gzip 算法。
  • -R /mnt:将池重新挂载到 /mnt 目录方便之后的系统安装操作
     


* 创建ZFS池时应该始终使用设备的 by-id 名称,否则导入储存池会发生错误
* 除使用 by-id 名称外,也可以考虑使用 by-partuuid (推荐) 或 by-uuid 名称,因为即使主机硬盘物理位置变化 这些名称的值也不会发生改变,反之亦然。(这仅当 ZFS 在磁盘上的某个分区中才有效,若 ZFS 占据整个磁盘则无效)

 

>zpool create -f -o ashift=12          \
             -O acltype=posixacl       \
             -O relatime=on            \
             -O xattr=sa               \
             -O dnodesize=legacy       \
             -O normalization=formD    \
             -O mountpoint=none        \
             -O canmount=off           \
             -O devices=off            \
             -O compression=zstd       \
             -O dedup=on               \
             -R /mnt                   \
             zroot /dev/disk/by-partuuid/132c9d87-f0ef-4878-ac36-4eb2d6625091

 

3.创建数据集(部分可选)

ZFS的数据集类似传统文件系统中的“分区”数据集虽然共享存储池的空间(也可单独设置配额),但是数据块是独立的(同存储池不同数据集下不能使用硬连接,mv 命令无法也直接将A数据集的文件移动到B数据集而是复制再删除);ZFS 最实用的功能之一便是启动环境。可以快速创建系统的可引导快照,也可以通过简单地重启到某启动环境来将整个系统回滚到那个快照。这使得系统更新变得更加安全,对软件开发与测试来讲也十分有用。通常情况下应该至少创建一个根目录数据集用于安装系统,存放用户数据的数据集为可选项,请根据自身需求自行决定,以下示例仅供参考。
 

>zfs create -o mountpoint=none zroot/ROOT
>zfs create -o mountpoint=none zroot/data
>zfs create -o mountpoint=/ -o canmount=noauto zroot/ROOT/ArchLinux
>zfs create -o mountpoint=/home zroot/data/home

 

4.验证 ZFS 池设置

不要跳过这一步,否则再导入存储池时必须使用 -f 参数。这会使导入的存储池卸载。

 

>zpool export zroot
>zpool import -R /mnt zroot

 


0x04 配置文件系统

1.挂载根目录为安装系统做准备

 

>zfs mount zroot/ROOT/ArchLinux
>zfs mount -a
# 挂载 EFI 分区
>mkdir /mnt/efi
mount /dev/disk/by-uuid/C3FF-2CAD /mnt/efi

 

2.配置文件系统参数

 

# 设置用于启动系统的数据集
>zpool set bootfs=zroot/ROOT/ArchLinux zroot
# 设置并生成存储池信息文件
>zpool set cachefile=/etc/zfs/zpool.cache zroot
# 将储存池信息文件拷到新的系统根目录中
>mkdir -p /mnt/etc/zfs && cp /etc/zfs/zpool.cache /mnt/etc/zfs/zpool.cache

0x05 安装系统以及系统设置

1.安装基础系统包,可以根据自身需求自行增删。

  • 如果是AMD的CPU就把 intel-ucode 换成 amd-ucode
  • 此处使用 zfs-linux 包可能会在后续更新中因为内核版本不匹配导致内核挂掉不能启动,如果有需要可以考虑系统启动后换成 LTS 内核以及 zfs-dkms 包以保证系统稳定,LTS 内核也可以和DKMS 模块一起使用,DKMS 理论可以支持所有内核版本,但是 DKMS 模块也有缺点,不可以在安装时直接使用,需要额外配置,以及每次更新内核后会实时编译内核模块,这会短时间占用大量系统资源,请自行选择。
  • 如果在安装过程中遇到了类似不支持xxxx版本的内核的提示可以将 zfs-linux 包切换为 zfs-linux-git 以支持更高版本内核

 

# 安装系统
>pacstrap -K /mnt base base-devel linux linux-firmware linux-headers zfs-linux 
efibootmgr os-prober intel-ucode dkms zsh networkmanager net-tools iperf3 
openssh nano wget unzip unrar  tmux htop nmap lsof neofetch git go rust archlinuxcn-keyring

2.初始系统设置(部分可选)

  • 安装完成后会使用 chroot 进入新系统中完成部分后续设置,请分清那些命令需要在 chroot 中执行
     
# 写入挂载信息
>genfstab -U -p /mnt >> /mnt/etc/fstab
 
# 软件源设置(可选)
>cat /etc/pacman.conf > /mnt/etc/pacman.conf
>cat /etc/pacman.d/mirrorlist > /mnt/etc/pacman.d/mirrorlist
 
# 设置 pacman 钩子,用于 dkms 更新后自动创建 initramfs 镜像(非DKMS安装则为可选项)
# 注意自行更改脚本内容中的内核名称
>mkdir -p /mnt/etc/pacman.d/hooks
>nano /etc/pacman.d/hooks/90-mkinitcpio-dkms-linux.hook
 
# 将以下信息粘贴进 /etc/pacman.d/hooks/90-mkinitcpio-dkms-linux.hook
[Trigger]
Operation=Install
Operation=Upgrade
Operation=Remove
Type=Package
Target=zfs-dkms
Target=linux

[Action]
Description=Update dkms modules in Linux initcpio
Depends=mkinitcpio
When=PostTransaction
NeedsTargets
Exec=/bin/sh -c 'while read -r trg; do case $trg in linux) exit 0; esac; done; /usr/bin/mkinitcpio -p linux'
 
# chroot 进入系统
>arch-chroot /mnt
 
# 设置存储池信息文件
>zpool set cachefile=/etc/zfs/zpool.cache zroot
 
# 更新软件源密钥
>pacman-key --lsign-key "[email protected]"
>pacman-key -r DDF7DB817396A49B2A2723F7403BD972F75D9D76
>pacman-key --lsign-key DDF7DB817396A49B2A2723F7403BD972F75D9D76
 
# 设置 root 密码
>passwd

 

3.设置 ZFS 的基本挂载服务和其他必要服务自启动

 

>systemctl enable zfs.target
>systemctl enable zfs-import.target
>systemctl enable zfs-import-cache
>systemctl enable zfs-mount.service
>systemctl enable sshd
>systemctl enable NetworkManager

 

4.配置内核钩子

重点部分,这里直接决定了你的系统能不能启动
  • 编辑 /etc/mkinitcpio.conf 文件,找到 MODULESHOOKS 区块,添加 ZFS 支持,修改完成后看起来应该像这样
  • 请不要随意改变以下模块的顺序,zfs 应在 filesystems 前,keyboard 应在 zfs 前,如果你不使用 Ext3 或 Ext4,也可以移除 fsck
     
MODULES=(zfs)
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block zfs filesystems)

 

>zgenhostid $(hostid)

 

  • 生成 initramfs 镜像,命令任选其一即可
     
# 指定内核名称生成
>mkinitcpio -p linux
 
# 自动生成(推荐)
>mkinitcpio -P

0x06 设置引导

  • 到这里你已经离成功不远了,ZFS 可以使用多种不同的引导程序启动,详情见 Arch Linux WiKi,这里我更推荐使用 ZFSBootMenu 它原生支持 ZFS,可以直接在引导内对 ZFS 文件系统进行便捷操作,对系统进行排错修复非常好用,且配置对简单,它的功能包括但不限于管理快照,基于快照复制新的根分区并启动,在引导内直接 chroot 进入操作系统等等。
     
# 挂载 EFI 分区(先前有挂载过,如提示已经挂载则跳过)
>mkdir /efi
>mount /dev/disk/by-uuid/C3FF-2CAD /efi
 
# 获取 ZFSBootMenu 引导文件
>mkdir -p /efi/EFI/ZBM
>wget https://github.com/zbm-dev/zfsbootmenu/releases/download/v2.3.0/zfsbootmenu-release-x86_64-v2.3.0-vmlinuz.EFI -O /efi/EFI/ZBM/zfsbootmenu.efi
 
# 设置启动时的 zfs 命令行参数(Command line)
# 小提示:之后设置内核参数也可以直接使用该命令添加而无需重新生成 initramfs
>zfs set org.zfsbootmenu:commandline="rw" zroot/ROOT
 
# 向主板 UEFI 中加入 ZFSBootMenu 条目
# 请注意 -d 以及 -p 参数分别对应物理硬盘和 EFI 分区位于该盘的第几个分区
>efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l '\EFI\ZBM\zfsbootmenu-release-x86_64-vmlinuz.EFI'
 
# 退出 chroot
>exit
 
# 取消挂载目录
>umount -R /mnt
 
# 取消zfs挂载
>zfs umount -a
 
# 导出池
>zpool export -a
 
# 之后你就可以重启进入你的新系统了

0X07 扩展

1.现在系统应该可以正常使用了,下方设置如果不需要可以不用继续进行

如果你觉得 zfs-linux 包已经足够了,那这一步可以跳过,如果你需要 DKMS 来动态加载 ZFS 模块,那就继续。
 

# 完全卸载 LINUX 内核以及 ZFS 包
pacman -R linux linux-headers linux-firmware zfs-linux zfs-utils --noconfirm
 
# 安装新内核以及 zfs-dkms
pacman -S linux-lts linux-lts-headers linux-firmware zfs-dkms
#等待 DKMS 模块编译完成重启即可

* 内核必须完全卸载否则直接在原内核上安装永远会提示无法找到 zfs 模块,导致无法正常启动
* dkms 编译在低性能主机上可能会耗时较久,请耐心等待
* 如果安装时有类似 “Failed to load preset” 错误可以尝试手动重新生成initramfs
* 如果安装时有类似“命令没有正确完成”以及 “modules not find xxx” 的错误请检查内核是否正确卸载/安装
   本文引用信息  ==>  展开 / 收缩