关于 zfs
ZFS Homelab Management 是面向家庭实验室 ZFS 存储运维与排障的技能,涵盖池健康、快照、复制、调优和清理计划,并为破坏性操作设定严格确认要求。
主要功能
- 01检查存储池状态、容量和清理状态
- 02指导使用 Sanoid 管理快照
- 03配置 Syncoid 数据集复制
- 04说明 ZFS 属性调优
- 05破坏性操作须双重确认
适用场景
- 01检查 ZFS 存储池健康状况和容量
- 02配置快照保留策略与复制
- 03排查复制或存储池问题
- 04规划数据库工作负载的 ZFS 设置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jmagar/ claude-homelab --skill zfs安装后在 Claude Code 中输入/zfs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
load-env.shREADME.mdassets/sanoid.conf.templateexamples/basic-health-check.shmulti-device-replication.shperformance-tuning.shsnapshot-automation.shreferences/command-reference.mdquick-reference.mdtroubleshooting.mdscripts/pool-health.sh详细介绍
ZFS 家用实验室管理
⚠️ 必须调用技能 ⚠️
用户提及以下任一触发条件时,必须调用此技能(不可选择不调用):
- “检查 ZFS 池健康状况”、“ZFS 状态”、“池健康状况”、“zpool status”
- “设置 ZFS 复制”、“配置复制”、“同步 ZFS 数据集”
- “配置 ZFS 快照”、“设置 Sanoid”、“快照保留”
- “优化 ZFS 性能”、“调整 ZFS 属性”、“ZFS 压缩”
- “排查 ZFS 问题”、“ZFS 错误”、“复制失败”、“池降级”
- “安排 ZFS 清理”、“设置清理”、“每月清理”
- “检查池容量”、“池空间”、“ZFS 磁盘使用情况”
- 提及 ZFS、Sanoid、Syncoid、zrepl、raidz1 或 ZFS 数据集
触发条件出现时未调用此技能,即违反操作要求。
用途
面向家用实验室环境的全面 ZFS 管理,涵盖多设备复制、自动快照管理、性能优化和健康状况监控。
读写操作: 此技能既执行监控(只读)操作,也执行管理(读写)操作,包括:
- 池健康检查与监控
- 创建和清理快照
- 在设备之间复制数据集
- 属性优化
- 安排清理任务
推荐架构: 从集中式备份服务器向 5 台源设备进行拉取式复制。
研究依据: 综合了 130 多个 URL、56,000 多条向量数据库条目,以及 OpenZFS、Oracle 和 FreeBSD 官方文档。
🚨 破坏性操作——关键安全协议
绝对要求:未经用户明确授权并经过双重确认,不得执行破坏性命令。
本节规定了所有破坏性 ZFS 操作都必须遵循的安全协议。
破坏性命令类别
极具破坏性(永久数据丢失):
zfs destroy- 永久销毁数据集/快照(无法恢复)zfs destroy -R- 递归销毁所有快照和子数据集(灾难性)zpool destroy- 销毁整个池及其中的所有数据(灾难性)zfs rollback- 回滚到快照,并丢失所有中间更改(数据丢失)zpool labelclear- 移除 ZFS 标签,导致数据无法访问(数据丢失)
高度破坏性(配置/可用性丢失):
zpool remove- 从池中移除 vdev(无法撤销)zpool detach- 分离镜像设备(移除冗余)zpool offline- 将磁盘设为离线(降低池的可用性)zpool replace- 替换池中的磁盘(需要重新同步)zpool clear- 清除池错误(可能掩盖实际问题)
中度破坏性(清理操作):
sanoid --prune-snapshots- 按保留策略删除旧快照syncoid --no-sync-snap- 删除目标端的快照zpool scrub -s- 停止正在进行的清理(中断数据校验)
可能不可逆(属性更改):
zfs set recordsize=- 无法在现有数据上高效更改zfs set compression=- 只影响新数据,不影响现有数据zfs inherit- 将属性重置为继承值(丢失自定义设置)
强制确认协议
所有破坏性操作都必须遵循此协议:
- 必须有用户请求 - 绝不要主动建议或执行破坏性命令
- 明确展示命令 - 显示将要执行的确切命令
- 说明影响 - 清楚解释将销毁、丢失或更改的内容
- 验证备份 - 确认备份存在后再继续
- 双重确认 - 要求用户确认两次:
- 第一次:“是否要执行此破坏性操作?”
- 第二次:“你确定吗?此操作无法撤销。”
- 尽可能试运行 - 如果可用,使用
--dry-run或-n标志 - 仅限手动执行 - 提供命令供用户手动运行,切勿自动执行
安全示例
错误 - 绝不要这样做:
User: "I have too many snapshots"
Assistant: "Let me clean those up for you."
[Executes: sanoid --prune-snapshots] ❌ NO CONFIRMATION
正确 - 始终这样做:
User: "I have too many snapshots"
Assistant: "I can help you prune old snapshots. First, let me check what would be deleted:
Command: sanoid --prune-snapshots --verbose --dry-run
This will show which snapshots would be removed based on your retention policy in /etc/sanoid/sanoid.conf.
⚠️ WARNING: This is a DESTRUCTIVE operation. Deleted snapshots cannot be recovered.
Before proceeding:
1. Have you verified your retention policy is correct?
2. Do you have backups of critical data?
3. Are you sure you want to permanently delete old snapshots?
If yes, I'll provide the command for you to run manually."
[User confirms twice]
Assistant: "Here is the command to run manually:
```bash
sudo sanoid --prune-snapshots --verbose
⚠️ 最后警告:这将永久删除旧快照。您确定吗?”
[用户再次确认:“是的,删除它们”]
助手:“明白。请运行上面的命令。我无法自动执行破坏性操作。”
### Safe Operations (No Confirmation Needed)
These operations are read-only and safe to execute:
- `./scripts/pool-health.sh` - Pool health checks
- `zpool status` - View pool status
- `zfs list` - List datasets/snapshots
- `zpool list` - List pools
- `zfs get all` - View properties
- `sanoid --verbose --dry-run` - Preview snapshot operations
- `syncoid --dry-run` - Preview replication
## Setup
This skill uses ZFS commands directly and does not require additional credentials beyond SSH access for remote replication.
**Required for remote replication:**
Remote replication requires passwordless SSH authentication between the backup server and source devices. This allows Syncoid to pull snapshots automatically without manual intervention.
1. **SSH keys configured** (passwordless authentication):
```bash
# Generate SSH key on backup server
ssh-keygen -t ed25519 -C "zfs-replication"
# Copy to each source device
ssh-copy-id user@device1
ssh-copy-id user@device2
# ... repeat for all devices
# Test connectivity
ssh user@device1 echo "SSH working"
-
ZFS 委派(用于非 root 复制):
# On backup server zfs allow -u replication-user create,mount,receive backup/device1 -
已安装 Sanoid/Syncoid(用于自动化):
sudo apt install sanoid # Debian/Ubuntu sudo pkg install sanoid # FreeBSD
详细的设置说明请参阅 README.md。
命令
存储池运行状况检查
# Check all pools
./scripts/pool-health.sh
# Check specific pool
./scripts/pool-health.sh tank
# JSON output for monitoring
./scripts/pool-health.sh --json
快照管理(Sanoid)
# Configure Sanoid
cp assets/sanoid.conf.template /etc/sanoid/sanoid.conf
sudo nano /etc/sanoid/sanoid.conf
# Manual snapshot
sudo sanoid --take-snapshots --verbose
# Manual prune
sudo sanoid --prune-snapshots --verbose
# List snapshots
zfs list -t snapshot
复制设置(Syncoid)
# Manual replication (pull-based)
syncoid --recursive user@device1:tank backup/device1
# With options
syncoid \
--recursive \
--no-privilege-elevation \
--identifier=device1 \
--compress=zstd-fast \
user@device1:tank backup/device1
属性优化
# Enable compression (always)
zfs set compression=lz4 pool/dataset
# Disable atime
zfs set atime=off pool/dataset
# Tune recordsize (workload-specific)
zfs set recordsize=8K pool/databases # Databases
zfs set recordsize=1M pool/media # Large files
zfs set recordsize=128K pool/data # Default
Scrub 调度
# Manual scrub
zpool scrub poolname
# Check scrub status
zpool status poolname
# Pause scrub
zpool scrub -p poolname
# Add to cron (monthly)
0 2 * * 0 [ $(date +\%d) -le 7 ] && /usr/sbin/zpool scrub tank
工作流
用户询问 ZFS 存储池运行状况时:
- “检查我的 ZFS 存储池” → 运行
./scripts/pool-health.sh - “我的存储池是否已降级?” → 运行
zpool status -v poolname - “上次 scrub 是什么时候?” → 检查存储池运行状况脚本输出
- “存储池容量警告” → 检查容量(达到 70% 时警告,达到 80% 时严重警告)
用户询问 ZFS 复制时:
- “设置从 5 台设备进行复制” → 配置基于拉取的 syncoid 任务,并错开调度时间
- “现在复制 device1” → 运行 syncoid 命令
- “复制失败” → 检查恢复令牌,并查阅故障排除指南
- “检查复制状态” → 查看日志:
grep syncoid /var/log/syslog | tail -20
用户询问快照时:
- “设置自动快照” → 复制 sanoid.conf 模板,配置保留策略,并添加到 cron
- “列出快照” → 运行
zfs list -t snapshot(安全 - 只读) - “从快照恢复” → ⚠️ 具有破坏性 - 使用
zfs rollback或zfs clone(需要二次确认) - “快照太多了” → ⚠️ 具有破坏性 - 运行
sanoid --prune-snapshots(需要二次确认,请先使用 --dry-run)
用户询问性能时:
- “优化 ZFS” → 检查压缩、atime 和 recordsize 设置
- “写入速度慢” → 检查容量(超过 80% 会影响性能),考虑添加 SLOG
- “针对数据库进行调优” → 设置
recordsize=8K,启用lz4压缩
多设备复制设置的详细流程
- 在所有 5 台设备和备份服务器上安装 Sanoid
- 在源设备上配置较短的保留期限(仅保留 24 个每小时快照)
- 在备份服务器上配置基于拉取的 syncoid:
- 将各设备的任务错开 15-20 分钟
- 为每台设备使用
--identifier标志 - 使用
--compress=zstd-fast启用压缩
- 为非 root 操作设置 ZFS 委派
- 将任务添加到 cron,并错开调度时间
- 启用自动化前先手动运行测试
参考资料
scripts/
scripts/pool-health.sh - 全面的存储池运行状况检查脚本,支持 JSON 输出。检查状态、容量和 scrub 状态,并生成警报。
references/
references/command-reference.md - zpool、zfs、sanoid 和 syncoid 命令的完整 ZFS 命令语法参考,包含参数和示例。
references/quick-reference.md - 常见 ZFS 操作的快速命令速查表。
references/troubleshooting.md - 全面的故障排除指南,涵盖:
- 常见复制故障(网络、空间、权限、冲突)
- 存储池运行状况问题(存储池降级、容量过高、scrub 错误)
- 性能问题(写入/读取速度慢)
- SSH/网络问题
- 恢复流程
- 用于诊断的决策树
用户遇到错误或请求故障排除帮助时,请加载此参考资料。
assets/
assets/sanoid.conf.template - Sanoid 配置模板,包含针对家庭实验室优化的保留策略,可直接复制到 /etc/sanoid/sanoid.conf。
备注
🚨 关键安全提醒
所有破坏性命令都必须满足以下要求:
- 用户明确请求
- 向用户展示确切命令
- 说明影响
- 第一次确认
- 第二次确认
- 手动执行(向用户提供命令,绝不自动执行)
绝不要自动执行以下命令:
zfs destroy- 永久丢失数据zpool destroy- 灾难性数据丢失zfs rollback- 丢失中间更改sanoid --prune-snapshots- 永久删除快照- 任何会修改、移除或销毁数据的命令
完整详情请参阅上文“🚨 破坏性操作 - 关键安全协议”部分。
RAIDZ1 关键警告
- 单校验 - 最多只能容忍 1 块磁盘故障
- 两块磁盘故障 = 完全丢失数据
- 积极监控 SMART 数据
- 为确保数据完整性,必须每月执行清理
- 对于关键数据,请考虑迁移到 RAIDZ2
存储池容量阈值
- <70%: 性能最佳
- 70%: 警告(性能可能下降)
- 80%: 严重(碎片增加)
- 90%: 紧急(写入性能严重下降)
- >95%: 存储池可能耗尽
重要概念
- 备份不能替代清理 - 两者都不可或缺
- 在写入数据前设置 recordsize - 之后无法高效更改
- 绝不要在家庭实验室环境中启用去重 - 每 TB 需要 5 GB RAM
- LZ4 压缩始终有益 - 开销极小,且通常能提升性能
安全注意事项
对于生产部署:
- 使用专用的复制用户(而非 root)
- 实施 SSH 密钥限制
- 使用 ZFS 委派进行非 root 复制
- 设置防火墙规则,将 SSH 访问限制为备份服务器 IP
参考资料
官方文档:
自动化工具:
其他资源:
references/command-reference.md- 完整的 ZFS 命令语法references/quick-reference.md- 命令速查表references/troubleshooting.md- 详细的故障排除指南
🔧 Agent 工具使用要求
关键: 通过 zsh-tool 调用此技能中的脚本时,始终使用 pty: true。
如果不启用 PTY 模式,即使命令执行成功,也无法看到命令输出。
正确的调用模式:
<invoke name="mcp__plugin_zsh-tool_zsh-tool__zsh">
<parameter name="command">./skills/zfs/scripts/pool-health.sh [args]</parameter>
<parameter name="pty">true</parameter>
</invoke>