这是本节的多页打印视图。 .
ZFS 存储管理
pg zfs 把一台 Linux 主机变成 ZFS 存储服务器:安装软件包、检查磁盘、创建带冗余的
pool,并管理 dataset 和 snapshot。它直接与内核交互,不读写 pg.yaml,也不依赖任何
PostgreSQL 实例。
命令按“资源 → 动作”组织:pg zfs pool create、pg zfs dataset create、
pg zfs snapshot rollback。没有封装的能力可通过 pg zfs raw 原样透传。
支持的系统
pg zfs install 从 /etc/os-release 识别发行版,并自动准备软件源后完成安装:
| 发行版 | ZFS 来源 | 实测版本 |
|---|---|---|
| Debian 12 (bookworm) | Debian contrib,DKMS |
2.1.11 |
| Debian 13 (trixie) | Debian contrib,DKMS |
2.3.9 |
| Ubuntu 24.04 (noble) | Ubuntu universe |
2.2.2,使用 Ubuntu 内核模块包 |
| Ubuntu 26.04 | Ubuntu universe |
2.4.1 |
| Fedora 44 | OpenZFS release RPM,DKMS | 2.4.4 |
| Rocky Linux 10 | OpenZFS release RPM + EPEL,DKMS | 2.2.11 |
这些是安装器测试时上游仓库提供的版本,实际安装到的版本由仓库决定;
pg zfs status 总会打印已安装的用户态与内核模块版本。
其他发行版只会被识别并给出手动安装指引,不会自动安装。仅支持 Linux。
安装
命令零参数、幂等:
- 检查权限(root,或可用的
sudo -n)。 - 自动启用所需软件源(Debian
contrib、Ubuntuuniverse、 Fedora/Rocky 的 OpenZFS release 仓库)。 - 安装 ZFS、内核头文件/模块和 ZED 守护进程。
- 加载模块并把 ZFS 的 systemd 单元设为开机自启。
- 打印用户态与内核模块版本。
在健康的机器上重复执行是 no-op。安装不提供 --version、--backports、
--force 等开关——需要特定 ZFS 版本时请用发行版包管理器升级,之后交由
pg zfs 管理。
随时查看状态:
RAID 级别与 ZFS 的对应关系
ZFS 没有标准的 RAID2 / RAID3 级别,对应关系如下:
--type |
ZFS 布局 | 冗余 | 类比 |
|---|---|---|---|
stripe(raid0) |
条带 vdev | 无 | RAID0 |
mirror(raid1) |
镜像 | 1 份以上副本 | RAID1 |
raidz1 |
单校验 | 1 块盘 | RAID5 |
raidz2(raid2) |
双校验 | 2 块盘 | RAID6 |
raidz3(raid3) |
三校验 | 3 块盘 | 三校验 RAID |
为方便起见也接受 raid0/raid1/raid2/raid3 别名。
快速开始
pool 挂载在 /tank,dataset 挂载在 /tank/backups。回滚会丢弃快照之后的所有
改动,执行前需要确认。
复用旧 pool 的磁盘
ZFS 会在盘上保留 vdev 分区和标签,export 不会清除它们,因此安全校验会拒绝
这些盘。创建新 pool 前先销毁旧 pool 并清理残留:
如果整盘 labelclear 报错,改清成员分区(/dev/vdd1、/dev/vde1)。旧 pool
已被销毁时跳过第 1 步。
磁盘安全
pg zfs disk list 会列出每块整盘的挂载点、ZFS 归属以及 pgcli 是否认为它可以安全
交给 ZFS 使用。
创建 pool 时拒绝:
- 根盘,或带有已挂载分区的磁盘;
- 分区、loop、ROM、CD-ROM 设备;
- 带有文件系统(
ext4、xfs、swap、LVM、LUKS、mdraid 等)的磁盘; - 已有 ZFS 标签的磁盘;
- 只读磁盘;
- 重复设备(包括通过不同路径指向的同一块盘);
- 已被其他 pool 使用的磁盘。
--force 只跳过确认提示,不会映射为 ZFS 的 -f,也不绕过任何安全检查。
创建 pool
自动布局
位置参数的数量决定布局:
| 盘数 | 布局 |
|---|---|
| 1 | stripe(告警:无冗余) |
| 2 | mirror |
| 3 | raidz1 |
| 4 及以上 | raidz2 |
用 --type 覆盖:
同一 vdev 内请尽量使用容量一致的磁盘(性能也应相近)。ZFS 不会拒绝混合容量, 但 vdev 的可用容量由最小的成员盘决定,大盘多出的空间会被浪费。同一 pool 的不同 vdev 之间可以容量不同。
多个 vdev
使用可重复的 --data 分组,并显式给出 --type。每个分组是一个 vdev,pool 在
这些 vdev 之上做条带:
--type 作用于每个 --data 组内部,而不是 pool 整体:每个组建成该布局的一个
vdev,pool 在这些 vdev 之上条带。所有组共用同一个 --type;pg zfs 不支持
一次创建中混用 mirror、raidz2 等布局,混合拓扑需使用
pg zfs raw zpool create。
pool 容量为各 vdev 可用容量之和;冗余按 vdev 计算,任一 vdev 失去超出其容错能力 的磁盘都会导致整个 pool 不可用。
SLOG、special、cache 与热备
--special 跟随 --type(这里是 mirror)。--log 两块及以上自动 mirror,单块为
stripe 并给出告警。--cache 与 --spare 接受独立的设备列表。
同一块盘只能出现在 data、special、log、cache、spare 中的一处。
建池后也可以用 pool add 追加热备盘:
默认属性
除非指定 --no-defaults:
| 对象 | 属性 | 值 |
|---|---|---|
| pool | ashift |
12 |
| pool | autoexpand |
on |
| pool | autotrim |
所有数据盘均为非旋转盘且支持 discard 时为 on |
| 根 dataset | compression |
zstd |
| 根 dataset | atime |
off |
| 根 dataset | xattr |
sa |
| 根 dataset | acltype |
posixacl |
| 根 dataset | dnodesize |
auto |
pool 属性用 --prop/-p 覆盖(对应 zpool -o),根 dataset 属性用
--fs-prop/-P 覆盖(对应 zpool -O):
-o 是 pgcli 的全局输出参数,所以 pool/dataset 属性使用 -p/-P。在
pg zfs raw 内部,ZFS 原生参数照常可用。
管理 pool
扩容与修复:
attach 针对 mirror vdev。给 raidz vdev 增加磁盘(raidz expansion)需要
OpenZFS 2.3 及以上;Debian 12(2.1)和 Ubuntu 24.04(2.2)不支持。新版本上可用
pg zfs raw zpool attach 操作。
卸载与彻底删除 pool
pg zfs pool export 会卸载所有 dataset 并把 pool 从主机上分离,但数据仍完整
保存在成员盘上:
已 export 的 pool 不会在开机时自动导入。重新接管时先列出可导入的 pool,再导入:
pg zfs pool destroy 会删除 pool、所有 dataset 和全部数据:
destroy 只能作用于已导入的 pool。如果 pool 已 export,需要先导入再销毁:
不加 --force 时这两个命令都会要求确认;EOF 和默认答案均为“否”。非交互自动化
必须显式传 --force。--force 只跳过确认,绝不会映射为 ZFS 的 -f,也不绕过
任何安全校验。export 可逆,destroy 不可逆。
持久化与开机自动导入
pool 和 dataset 默认在重启后自动恢复,无需额外配置:
pg zfs install会启用zfs-load-module、zfs-import-cache、zfs-mount和zfs-zed(单元存在时)。zpool create会把 pool 记录到/etc/zfs/zpool.cache;开机时zfs-import-cache据此导入。- ZFS 不使用
/etc/fstab。每个 dataset 的mountpoint是 ZFS 属性,开机时 由zfs-mount完成挂载。pool 的根 dataset 挂载在/<pool>,子 dataset 挂载在其下(例如/fast/data)。 - pool 状态保存在成员盘上,异常断电或非正常关机后数据仍可导入。
检查配置:
重启后 pg zfs pool list 应能看到该 pool,findmnt /fast 应显示已挂载。
真实硬件上建议用 /dev/disk/by-id/... 等稳定路径创建 pool。/dev/sdX
名称可能在重启后变化,设备找不到时 pool 不会导入。把磁盘移到其他主机前先执行
pg zfs pool export tank,对方即可用 pg zfs pool import tank 接管。
Dataset 与 snapshot
带子 dataset 的 dataset 必须加 --recursive 才能销毁。
回滚
pg zfs snapshot rollback tank/data@snap1 把 dataset 恢复到快照记录的状态,
之后的所有改动都会被丢弃。如果存在更新的快照,ZFS 会拒绝回滚;加 --recursive
会先删除这些更新的快照。依赖该快照的 clone 也会阻止回滚——先删除 clone,或用
pg zfs raw zfs rollback -R(会一并删除依赖的 clone)。非交互运行需加
--force 跳过确认。
克隆
pg zfs dataset clone tank/data@snap1 tank/clone 从快照创建一个新的可写
dataset。未改动的数据块按写时复制共享,不会复制整份数据。用 --prop 设置新
dataset 的属性:
clone 依赖的快照在 clone 存在期间不能销毁。需要删除旧快照时,先用
pg zfs raw zfs promote tank/clone 提升 clone,使其独立于原 dataset。
raw 透传
raw 绕过所有安全校验和确认,是未封装参数的逃生通道——请像以 root 身份直接运行
zpool/zfs 一样谨慎。二进制管道也可以工作,例如:
权限模型
所有会调用 zpool 或 zfs 的命令都会先检查权限:
-
root:直接执行;
-
非 root 且
sudo -n可用:所有 ZFS 命令通过sudo -n执行; -
否则立即失败:
pgcli 从不弹出 sudo 密码提示。pg zfs status 和 pg zfs disk list 在无权限时仍会
输出静态信息,并把 pool 详情标记为不可用。
命令参考
| 命令 | 用途 |
|---|---|
pg zfs install |
安装 ZFS(零参数、幂等) |
pg zfs status |
发行版、软件包、模块与 pool 概览 |
pg zfs disk list [--all] |
整盘、挂载、ZFS 归属与安全性 |
pg zfs pool create NAME DEVICE... |
创建 pool |
pg zfs pool list |
列出 pool |
pg zfs pool status [NAME] [--brief] |
详细状态 |
pg zfs pool add NAME DEVICE... |
增加 vdev |
pg zfs pool attach/detach NAME DEVICE [NEW] |
扩大/缩小 mirror |
pg zfs pool replace NAME OLD NEW |
替换磁盘 |
pg zfs pool offline/online NAME DEVICE |
下线/上线磁盘 |
pg zfs pool export/import [NAME] |
在系统间迁移 pool |
pg zfs pool scrub NAME [--stop] |
校验数据完整性 |
pg zfs pool destroy NAME |
销毁 pool 及全部数据 |
pg zfs dataset create/list/set/clone/destroy |
dataset 生命周期 |
pg zfs snapshot create/list/rollback/destroy |
snapshot 生命周期 |
pg zfs raw zpool/zfs ARGS... |
绕过封装的透传 |
故障排查
pg zfs install 找不到软件包。 检查发行版归档源是否可达、contrib/universe
是否已启用。安装器只修改发行版官方归档源(绝不动第三方源),并在每个被修改的文件旁
留下 *.pgcli.bak。
DKMS 构建失败。 确认当前内核的头文件已安装(Debian/Ubuntu 为
linux-headers-$(uname -r),Fedora/Rocky 为 kernel-devel-$(uname -r))。安装器
会给出构建日志位置;它不会重启或更换内核。内存很小的 VM 请先加 swap。
Secure Boot 已开启。 DKMS 模块需要签名。pgcli 只报告该情况,不会自动登记密钥; 请用 MOK 签名模块,或在测试机上关闭 Secure Boot。
模块未加载。 执行 modprobe zfs 后运行 pg zfs status。安装器会启用
zfs-load-module、zfs-import-cache、zfs-mount 和 zfs-zed,使 pool 开机
自动导入。
磁盘因分区或旧标签被拒绝。 如果确认磁盘空闲,清理残留:
在 OpenZFS 2.2 及更新版本上,若标签位于 ZFS 成员分区内,清理整盘会报
failed to clear label for /dev/vdb。此时改为清理该分区,再清分区表:
绝不要对已导入 pool 的成员盘这样做——pg zfs disk list 会显示所属 pool,安全检查
也会拒绝这类磁盘。
SELinux(Fedora/Rocky)。 ZFS 挂载点使用标准文件上下文。若服务无法访问某个
dataset,请查看 ausearch/journalctl 中的 AVC 拒绝记录,而不是全局关闭 SELinux。
重启后 pool 没有自动导入。 以 root 运行 systemctl status zfs-import-cache
和 zpool import。用 /dev/sdX 名称创建的 pool 会受设备重命名影响;真实硬件上
建议使用稳定路径(/dev/disk/by-id/...)创建 pool。