> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/zfs/an-zhuang-zhi-yin/ji-yu-rhel-de-yan-sheng-fa-xing-ban/zfs-root-on-rockylinux.md).

# 构建以 ZFS 为根文件系统的 Rocky Linux

**ZFSBootMenu**

[ZFSBootMenu](https://zfsbootmenu.org/) 是一种替代的引导加载器，不存在上述限制，并且支持启动环境。如果计划使用 ZBM，请不要参照本文，因为磁盘布局不兼容。有关安装详情，请参考其官方网站。

**自定义**

除非另有说明，否则不建议在重启前自定义系统配置。

**仅使用经过充分测试的 ZFS 存储池功能**

应仅使用经过充分测试的 ZFS 存储池功能。如果数据完整性至关重要，应避免使用新功能。参见，例如 [此评论](https://github.com/openzfs/openzfs-docs/pull/464#issuecomment-1776918481)。

**仅支持 UEFI**

本指南仅支持 UEFI 启动。

## 准备

1. 禁用安全启动。在启用安全启动时无法加载 ZFS 模块。
2. 由于最新 Live CD 的内核可能与 ZFS 不兼容，我们使用 Alpine Linux Extended，它默认自带 ZFS。 下载最新的 [Alpine Linux live 镜像 extended 版本](https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-extended-3.18.4-x86_64.iso)，并验证 [校验和](https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-extended-3.18.4-x86_64.iso.asc)，然后从其启动。

   ```sh
   gpg --auto-key-retrieve --keyserver hkps://keyserver.ubuntu.com --verify alpine-extended-*.asc

   dd if=input-file of=output-file bs=1M
   ```
3. 以 root 用户登录，初始无密码。
4. 配置网络

   ```sh
   setup-interfaces -r
   # 参数 "-r" 以正确启动网络服务
   # 示例：
   network interface: wlan0
   WiFi name:         <ssid>
   ip address:        dhcp
   <此处按回车完成安装>
   manual netconfig:  n
   ```
5. 如果使用无线网络但未显示，请参考 [Alpine Linux wiki](https://wiki.alpinelinux.org/wiki/Wi-Fi#wpa_supplicant) 获取更多信息。`wpa_supplicant` 可通过 `apk add wpa_supplicant` 安装，无需网络连接。
6. 配置 SSH 服务器

   ```sh
   setup-sshd
   # 示例：
   ssh server:        openssh
   allow root:        "prohibit-password" 或 "yes"
   ssh key:           "none" 或 "<公钥>"
   ```
7. 设置 root 密码或配置 `/root/.ssh/authorized_keys`。
8. 从其他计算机连接

   ```sh
   ssh root@192.168.1.91
   ```
9. 配置 NTP 客户端以同步时间

   ```sh
   setup-ntp busybox
   ```
10. 设置 apk 镜像源，系统会显示可用镜像列表，按空格键继续

    ```sh
    setup-apkrepos
    ```
11. 本指南中使用 udev 生成的可预测磁盘名称

    ```sh
    apk update
    apk add eudev
    setup-devd udev
    ```
12. 目标磁盘 列出可用磁盘

    ```sh
    find /dev/disk/by-id/
    ```

    如果使用 virtio 作为磁盘总线，请关闭虚拟机并为磁盘设置序列号。

    * 对于 QEMU：使用 `-drive format=raw,file=disk2.img,serial=AaBb`
    * 对于 libvirt：编辑 domain XML 参见 [示例页面](https://bugzilla.redhat.com/show_bug.cgi?id=1245013)。 声明磁盘数组

    ```sh
    DISK='/dev/disk/by-id/ata-FOO /dev/disk/by-id/nvme-BAR'
    ```

    单盘安装使用

    ```sh
    DISK='/dev/disk/by-id/disk1'
    ```
13. 设置挂载点

    ```sh
    MNT=$(mktemp -d)
    ```
14. 设置分区大小：

    设置 swap 大小（GB），如果不希望 swap 占用过多空间，可设为 1

    ```sh
    SWAPSIZE=4
    ```

    设置磁盘末端保留空间（最少 1GB）

    ```sh
    RESERVE=1
    ```
15. 从 live 系统安装 ZFS 支持

    ```sh
    apk add zfs
    ```
16. 安装分区工具

    ```sh
    apk add parted e2fsprogs cryptsetup util-linux
    ```

## 安装系统

1. 分区磁盘

   注意：必须清除目标磁盘上所有已有的分区表和数据结构。 对于闪存存储，可使用以下 `blkdiscard` 命令：

   ```sh
   partition_disk () {
    local disk="${1}"
    blkdiscard -f "${disk}" || true

    parted --script --align=optimal  "${disk}" -- \
    mklabel gpt \
    mkpart EFI 1MiB 4GiB \
    mkpart rpool 4GiB -$((SWAPSIZE + RESERVE))GiB \
    mkpart swap  -$((SWAPSIZE + RESERVE))GiB -"${RESERVE}"GiB \
    set 1 esp on \

    partprobe "${disk}"
   }

   for i in ${DISK}; do
      partition_disk "${i}"
   done
   ```
2. 为本次安装设置临时加密 swap（仅用于安装）。当可用内存较小时非常有用：

   ```sh
   for i in ${DISK}; do
      cryptsetup open --type plain --key-file /dev/random "${i}"-part3 "${i##*/}"-part3
      mkswap /dev/mapper/"${i##*/}"-part3
      swapon /dev/mapper/"${i##*/}"-part3
   done
   ```
3. 加载 ZFS 内核模块

   ```sh
   modprobe zfs
   ```
4. 创建根池
   * 未加密示例：

     ```sh
     # shellcheck disable=SC2046
     zpool create \
         -o ashift=12 \
         -o autotrim=on \
         -R "${MNT}" \
         -O acltype=posixacl \
         -O canmount=off \
         -O dnodesize=auto \
         -O normalization=formD \
         -O relatime=on \
         -O xattr=sa \
         -O mountpoint=none \
         rpool \
         mirror \
        $(for i in ${DISK}; do
           printf '%s ' "${i}-part2";
          done)
     ```
5. 创建根系统容器

   ```sh
   # dracut 要求系统根数据集具有非 legacy mountpoint
   zfs create -o canmount=noauto -o mountpoint=/ rpool/root
   ```

   创建系统数据集，并使用 `mountpoint=legacy` 管理挂载点：

   ```sh
   zfs create -o mountpoint=legacy rpool/home
   zfs mount rpool/root
   mount -o X-mount.mkdir -t zfs rpool/home "${MNT}"/home
   ```
6. 格式化并挂载 ESP。只使用其中一个作为 /boot，其余可稍后设置镜像：

   ```sh
   for i in ${DISK}; do
    mkfs.vfat -n EFI "${i}"-part1
   done

   for i in ${DISK}; do
    mount -t vfat -o fmask=0077,dmask=0077,iocharset=iso8859-1,X-mount.mkdir "${i}"-part1 "${MNT}"/boot
    break
   done
   ```

## 系统配置

1. 下载并解压 RHEL 最小根文件系统：

   ```sh
   apk add curl
   curl --fail-early --fail -L \
   https://dl.rockylinux.org/vault/rocky/9.2/images/x86_64/Rocky-9-Container-Base-9.2-20230513.0.x86_64.tar.xz \
   -o rootfs.tar.gz
   curl --fail-early --fail -L \
   https://dl.rockylinux.org/vault/rocky/9.2/images/x86_64/Rocky-9-Container-Base-9.2-20230513.0.x86_64.tar.xz.CHECKSUM \
   -o checksum

   # BusyBox sha256sum 处理 checksum 文件时要求文件名与校验值之间有两个空格
   grep 'Container-Base' checksum \
   | grep '^SHA256' \
   | sed -E 's|.*= ([a-z0-9]*)$|\1  rootfs.tar.gz|' > ./sha256checksum

   sha256sum -c ./sha256checksum

   tar x  -C "${MNT}" -af rootfs.tar.gz
   ```
2. 启用社区仓库

   ```sh
   sed -i '/edge/d' /etc/apk/repositories
   sed -i -E 's/#(.*)community/\1community/' /etc/apk/repositories
   ```
3. 生成 fstab

   ```sh
   apk add arch-install-scripts
   genfstab -t PARTUUID "${MNT}" \
   | grep -v swap \
   | sed "s|vfat.*rw|vfat rw,x-systemd.idle-timeout=1min,x-systemd.automount,noauto,nofail|" \
   > "${MNT}"/etc/fstab
   ```
4. chroot 进入安装环境

   ```sh
   cp /etc/resolv.conf "${MNT}"/etc/resolv.conf
   for i in /dev /proc /sys; do mkdir -p "${MNT}"/"${i}"; mount --rbind "${i}" "${MNT}"/"${i}"; done
   chroot "${MNT}" /usr/bin/env DISK="${DISK}" bash
   ```
5. 取消所有 shell 别名，以免干扰安装

   ```sh
   unalias -a
   ```
6. 安装基础软件包

   ```sh
   dnf -y install --allowerasing @core kernel-core kernel-modules
   ```
7. 安装 ZFS 软件包

   ```sh
   dnf install -y https://zfsonlinux.org/epel/zfs-release-2-3"$(rpm --eval "%{dist}"|| true)".noarch.rpm
   dnf config-manager --disable zfs
   dnf config-manager --enable zfs-kmod
   dnf install -y zfs zfs-dracut
   ```
8. 将 ZFS 模块添加到 dracut

   ```sh
   echo 'add_dracutmodules+=" zfs "' >> /etc/dracut.conf.d/zfs.conf
   echo 'force_drivers+=" zfs "' >> /etc/dracut.conf.d/zfs.conf
   ```
9. 将其他驱动添加到 dracut

   ```sh
   if grep mpt3sas /proc/modules; then
     echo 'force_drivers+=" mpt3sas "'  >> /etc/dracut.conf.d/zfs.conf
   fi
   if grep virtio_blk /proc/modules; then
     echo 'filesystems+=" virtio_blk "' >> /etc/dracut.conf.d/zfs.conf
   fi
   ```
10. 生成 hostid

    ```sh
    zgenhostid -f -o /etc/hostid
    ```
11. 构建 initrd

    ```sh
    find -D exec /lib/modules -maxdepth 1 \
    -mindepth 1 -type d \
    -exec sh -vxc \
    'if test -e "$1"/modules.dep;
       then kernel=$(basename "$1");
       dracut --verbose --force --kver "${kernel}";
     fi' sh {} \;
    ```
12. 对 SELinux，在重启时重新标记文件系统

    ```sh
    fixfiles -F onboot
    ```
13. 安装语言包（例如英文）

    ```sh
    dnf install -y glibc-minimal-langpack glibc-langpack-en
    ```
14. 设置语言、键盘布局、时区和主机名

    ```sh
    rm -f /etc/localtime
    systemd-firstboot \
    --force \
    --locale=en_US.UTF-8 \
    --timezone=Etc/UTC \
    --hostname=testhost \
    --keymap=us
    ```
15. 设置 root 密码

    ```sh
    printf 'root:yourpassword' | chpasswd
    ```

## 引导加载器

1. 安装 rEFInd 引导加载器：

   ```sh
   # 参考 http://www.rodsbooks.com/refind/getting.html
   # 使用 Binary Zip File 选项
   curl -L https://sourceforge.net/projects/refind/files/0.14.0.2/refind-bin-0.14.0.2.zip/download --output refind.zip

   dnf install -y unzip
   unzip refind.zip
   mkdir -p /boot/EFI/BOOT
   find ./refind-bin-0.14.0.2/ -name 'refind_x64.efi' -print0 \
   | xargs -0I{} mv {} /boot/EFI/BOOT/BOOTX64.EFI
   rm -rf refind.zip refind-bin-0.14.0.2
   ```
2. 添加启动项：

   ```sh
   tee -a /boot/refind-linux.conf <<EOF
   "Rocky Linux" "root=ZFS=rpool/root"
   EOF
   ```
3. 退出 chroot：

   ```sh
   exit
   ```
4. 卸载文件系统并创建初始系统快照（稍后可从此快照创建启动环境，参考 [Root on ZFS 维护页面](https://openzfs.github.io/openzfs-docs/Getting%20Started/zfs_root_maintenance.html)）：

   ```sh
   umount -Rl "${MNT}"
   zfs snapshot -r rpool@initial-installation
   ```
5. 导出所有 ZFS 存储池：

   ```sh
   zpool export -a
   ```
6. 重启系统：

   ```sh
   reboot
   ```

## 安装后配置

1. 安装软件包组：

   ```sh
   dnf group list --hidden -v       # 查询可用软件包组
   dnf group install gnome-desktop
   ```
2. 添加新用户并配置 swap。
3. 挂载其他 EFI 系统分区，然后设置服务以同步其内容。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/zfs/an-zhuang-zhi-yin/ji-yu-rhel-de-yan-sheng-fa-xing-ban/zfs-root-on-rockylinux.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
