本页目录
系统盘备份与恢复
系统盘(NVMe ext4)每日 rsync 到 ZFS mirror(
tank/backup/system)并打快照,保留 30 份。本文覆盖备份机制、日常检查、三级恢复场景(单文件→数据集回滚→整机裸机恢复),末尾列出不在备份范围内的内容。调度见 timers-and-crons.md。
方案总览
| 项 | 值 |
|---|---|
| 源 | /(ext4,vg_sys/lv_root,898.5G)+ /boot(vfat,nvme0n1p1) |
| 目标 | /tank/backup/system(2×4T WD Red ZFS mirror,lz4 压缩) |
| 方式 | rsync 文件级同步(首次全量,后续增量)+ 每次完成后 zfs snapshot |
| 版本 | 保留最近 30 个快照,多余自动销毁 |
| 调度 | systemd timer,每日 04:00,Persistent=true + idle IO 优先级 |
| 脚本 | /usr/local/sbin/backup-system.sh |
首次全量于 2026-07-09 执行,源约 500G。为什么不用块级镜像:vg_sys 空间已全部分配、无 LVM 快照余量;文件级备份可直接翻看、可单文件恢复,ZFS 快照又补齐了版本化,没有块级方案的必要。
备份机制
脚本每日做三件事:
rsync -aHAXx --delete --numeric-ids / → $DEST/root/,再同步/boot/ → $DEST/boot/zfs snapshot tank/backup/system@<时间戳>- 按创建时间清理,只留最近 30 个快照
关键参数:-x 不跨文件系统(自动避开 /proc、/sys、/tank 等,挂载点保留为空目录);-HAX 保留硬链接/ACL/xattr,恢复出来才是完整系统;退出码 24(拷贝期间文件消失)视为正常——在线备份必然遇到。
排除项(只排内容,目录本身保留):
| 路径 | 原因 |
|---|---|
/tmp/*、/var/tmp/* | 临时文件,含 portage 编译目录 |
/var/cache/distfiles/*、/var/cache/binpkgs/* | Gentoo 源码包/二进制包缓存,可重下重编 |
/lost+found | ext4 元数据 |
docker 数据(/var/lib/docker)在备份范围内。
一致性:rsync 在线备份是崩溃一致级别。系统盘上没有数据库(immich postgres 在 tank 上),风险可接受;若未来在系统盘上跑有状态服务,备份前应加 dump 步骤。
日常检查
长期:备份失败目前无告警,可给 service 加
OnFailure=钩子接入 Bark 推送(见 monitoring.md)。
已知坑:非 UTF-8 文件名
tank 池 utf8only=on(建池属性,不可改),非 UTF-8 文件名会被 ZFS 拒收,rsync 报错 23,整次备份失败且不打快照。首次全量(2026-07-09)就踩过:Wine 里腾讯游戏装的 GBK 编码目录/快捷方式名,mkdir 报 Invalid or incomplete multibyte or wide character。
排查与修复(转成 UTF-8 而非排除,一劳永逸):
# 全盘扫非 UTF-8 文件名(-x 必须带,否则空匹配全过)
|
# 逐个转名(GBK→UTF-8),在问题目录下:
for; do n= || continue; [ && [ && ; done
触发源头是 GBK locale 下跑 Wine 中文游戏安装器,以后装新游戏后值得跑一次扫描;备份日志(
journalctl -u backup-system)里的recv_generator: mkdir ... failed会直接指出问题路径。
场景 1:误删/改坏单个文件
快照以隐藏目录形式在线可读,直接拷回:
.zfs在ls -a里不可见,但可以直接cd进去。最新一次备份(未快照的当前状态)在/tank/backup/system/root/直接读。
场景 2:坏状态被同步进了备份
误删/中毒后备份先于发现执行,当前备份树已是坏的——不用 rollback(会销毁更新的快照),直接从更早的快照目录按场景 1 拷回即可。只有确认要整体退回时才:
场景 3:整机裸机恢复(系统盘损坏/更换)
需要带 ZFS 支持的 LiveUSB(SystemRescue 即可)。全程约 1–2 小时,大头是 HDD 读回 400G+。
1. 重建分区与 LVM(fstab 用设备名,VG/LV 名保持 vg_sys/lv_root 即可,无 UUID 依赖):
&&
&&
2. 导入池并回写:
3. chroot 重装引导(GRUB EFI,/boot/EFI/Gentoo):
for; do ; done
4. 收尾:
重启后确认:systemctl --failed 无异常、zpool import tank 后 zpool status ONLINE、systemctl list-timers 备份 timer 在位。
不在备份范围内
| 内容 | 现状 |
|---|---|
| tank 池数据(photos/media/immich) | 仅 mirror 冗余,无第二副本/异地备份,盘全坏或误删即丢 |
| 排除项(/tmp、portage 缓存等) | 可重建,恢复后首次 emerge 会重新下载 |
| swap LV | 无需备份,恢复时 mkswap 重建 |
长期:photos 等不可再生数据只有单池 mirror 一份,建议补异地(restic → 云对象存储,或异地机器
zfs send)。
相关文档
- timers-and-crons.md — 定时任务全局视图
- monitoring.md — 告警体系(备份失败告警待接入)
- server-lifecycle.md — 服务器生命周期