跳转到内容
搜索 Fedora 文档

    浏览当前文档目录

    Fedora 备份与恢复:btrfs 快照、tar 与 SELinux 标签

    备份最容易犯的错不是”没备份”,而是备了但恢复不回来。Fedora 上尤其如此——因为还有一层 SELinux 标签,普通的 tar -cf 会把它丢掉。

    下面每一条都在 F45 上实测过。

    层次内容手段
    系统状态装了什么包、仓库配置rpm -qa 清单 + 配置文本
    文件与数据/etc、/home、/var/libbtrfs 快照 / tar / rsync
    整机回滚整个根文件系统btrfs 快照

    三类不能互相替代:包清单恢复不了数据,快照回滚不了”装错了一个包”这种细粒度问题。

    F45 默认是 btrfs(详见存储),快照是零成本的——只记录写时复制。

    先看现状:

    Terminal window
    findmnt -no FSTYPE /
    sudo btrfs subvolume list /
    btrfs
    ID 256 gen 364 top level 5 path root
    ID 257 gen 300 top level 5 path boot
    ID 258 gen 368 top level 5 path home
    ID 259 gen 368 top level 5 path var

    一个容易踩的坑:快照套在自己里面

    Section titled “一个容易踩的坑:快照套在自己里面”

    如果直接这样截图:

    Terminal window
    sudo mkdir -p /snapshots
    sudo btrfs subvolume snapshot -r / /snapshots/root-$(date +%Y%m%d)

    结果快照会落在根子卷内部:

    ID 260 gen 369 top level 256 path root/snapshots/root-20261027

    top level 256 就是 root 子卷。这意味着下次截根快照时会把这次快照也包含进去,快照体积越滚越大。

    两种快照位置对比:快照放在 root 子卷内会递归增长,放在顶层 snapshots 子卷则互不包含

    正确做法:先建一个独立的顶层子卷

    Section titled “正确做法:先建一个独立的顶层子卷”
    Terminal window
    sudo mkdir -p /mnt/top
    sudo mount -o subvolid=5 /dev/sda3 /mnt/top # 挂顶层(subvolid=5)
    sudo btrfs subvolume create /mnt/top/snapshots
    sudo umount /mnt/top

    之后快照落在 snapshots 子卷里,与 root 平级:

    Terminal window
    sudo btrfs subvolume snapshot -r / /mnt/top/snapshots/root-$(date +%Y%m%d-%H%M)
    sudo btrfs subvolume list /mnt/top | grep snapshots
    ID 261 gen 371 top level 5 path snapshots
    ID 262 gen 371 top level 261 path snapshots/root-20261027-1747

    top level 261 是 snapshots 子卷——不再递归。

    快照占多少空间:

    Terminal window
    sudo btrfs filesystem usage /
    Overall:
    Device size: 19.90GiB
    Device allocated: 5.02GiB
    Device unallocated: 14.88GiB

    快照本身不占 allocated;只有原文件被修改后才会分叉出新数据块。所以刚截完的快照几乎不增加占用。

    这是 Fedora 上最容易出问题的一步。同一个文件,三种情况:

    Terminal window
    # 造一个带特定标签的文件
    sudo mkdir -p /tmp/seltest/src
    echo hi | sudo tee /tmp/seltest/src/file >/dev/null
    sudo chcon -t httpd_sys_content_t /tmp/seltest/src/file
    # 打包:一个不带参数,一个带 --selinux --xattrs
    sudo tar -cf /tmp/seltest/no-selinux.tar -C /tmp/seltest/src .
    sudo tar --selinux --xattrs -cf /tmp/seltest/with-selinux.tar -C /tmp/seltest/src .
    # 各自解开再比较标签
    sudo mkdir -p /tmp/seltest/a /tmp/seltest/b
    sudo tar -xf /tmp/seltest/no-selinux.tar -C /tmp/seltest/a
    sudo tar --selinux --xattrs -xf /tmp/seltest/with-selinux.tar -C /tmp/seltest/b
    sudo ls -Z /tmp/seltest/src/file /tmp/seltest/a/file /tmp/seltest/b/file
    original : unconfined_u:object_r:httpd_sys_content_t:s0
    no-flag : unconfined_u:object_r:user_tmp_t:s0
    with-flag: unconfined_u:object_r:httpd_sys_content_t:s0

    中间那行就是灾难:标签从 httpd_sys_content_t 变成了 user_tmp_t(从目标目录继承的默认标签)。文件内容完好,但服务读不了。

    正确的打包与解包:

    Terminal window
    sudo tar --selinux --xattrs --acls -czf backup-etc.tar.gz -C / etc
    sudo tar --selinux --xattrs --acls -xzpf backup-etc.tar.gz -C /mnt/restore

    -p 是保留权限位。--selinux 与 --xattrs 缺一不可——前者处理 SELinux 上下文,后者处理扩展属性(capabilities 也在里面)。

    包清单:恢复系统状态的唯一依据

    Section titled “包清单:恢复系统状态的唯一依据”
    Terminal window
    rpm -qa | wc -l
    rpm -qa --qf '%{NAME}
    ' | sort > /var/backups/pkgs.txt
    631

    F45 的基础系统是 631 个包。恢复时:

    Terminal window
    sudo dnf install $(cat /var/backups/pkgs.txt)

    还会想看仓库配置和最近的事务:

    Terminal window
    cp /etc/yum.repos.d/*.repo /var/backups/ 2>/dev/null
    ls /usr/share/dnf5/repos.d/ > /var/backups/repos-list.txt # F45 的自带仓库
    sudo dnf history list | head -5
    ID Command line Date and time Action(s) Altered
    10 dnf -y install dbus-daemon 2026-10-26 18:21:45 1
    9 dnf -y install dbus-tools 2026-10-26 18:20:19 1

    一、恢复 SELinux 标签(如果备份时标签没保住,或者恢复到了不同路径):

    Terminal window
    sudo restorecon -Rv /etc /var/www /home

    二、确认关键服务能起来:

    Terminal window
    sudo systemctl daemon-reload
    systemctl list-units --failed

    没验证过的备份等于没有备份。 最小验证集:

    Terminal window
    # 1) 压缩包能读吗
    tar -tzf backup-etc.tar.gz | wc -l
    # 2) 能解到临时目录吗
    mkdir -p /tmp/verify && tar -xzpf backup-etc.tar.gz -C /tmp/verify
    # 3) 关键文件在吗、内容对吗
    diff -q /tmp/verify/etc/hostname /etc/hostname
    # 4) 标签还在吗
    ls -Z /tmp/verify/etc/ssh/sshd_config

    btrfs 快照的验证更直接——挂出来看:

    Terminal window
    sudo mount -o ro,subvol=/snapshots/root-20261028-0300 /dev/sda3 /mnt/check
    ls /mnt/check/etc | head
    sudo umount /mnt/check

    用 systemd timer 而不是 cron(F45 最小化镜像不带 crontab),写法见systemd 服务与定时器:

    /etc/systemd/system/backup-etc.timer
    [Unit]
    Description=Nightly etc backup
    [Timer]
    OnCalendar=*-*-* 03:30:00
    Persistent=true
    [Install]
    WantedBy=timers.target

    配套的 .service 里放那条 tar --selinux --xattrs --acls ...。Persistent=true 保证关机错过的备份会在开机后补跑。