Snapper

出自 ArchWiki

Snapper 是 openSUSE 的 Arvin Schnell 创建的工具,用于帮助管理 Btrfs 子卷和精简配置的 LVM 卷的快照。它可以创建和比较快照,在快照之间恢复,并支持自动快照时间线。

安装

安装 snapper 软件包。开发版本 snapper-gitAUR 也可用。

此外,GUI 可通过 snapper-gui-gitAURbtrfs-assistantAURsnapper-toolsAUR 获得。

创建新配置

在为 Btrfs 子卷创建 snapper 配置之前,子卷必须已经存在。如果不存在,您应该在生成 snapper 配置之前创建它。

要为 /path/to/subvolume 处的 Btrfs 子卷创建名为 config 的新 snapper 配置,请运行

# snapper -c config create-config /path/to/subvolume

这将

  • 基于 /usr/share/snapper/config-templates 中的默认模板,在 /etc/snapper/configs/config 创建一个配置文件。
  • /path/to/subvolume/.snapshots 创建一个子卷,用于存储此配置的未来快照。快照的路径是 /path/to/subvolume/.snapshots/#/snapshot,其中 # 是快照编号。
  • config 添加到 /etc/conf.d/snapper 中的 SNAPPER_CONFIGS

例如,要为挂载在 / 的子卷创建配置文件,请运行

# snapper -c root create-config /
注意: 如果您正在使用 archinstall 中建议的 Btrfs 分区布局,则 @.snapshots 子卷将已挂载到 /.snapshots,并且 snapper create-config 命令将失败 [1]。要将 @.snapshots 子卷用于 Snapper 备份,请执行以下操作
  • 卸载 @.snapshots 子卷并删除现有的挂载点。
  • 创建 Snapper 配置。
  • 删除 Snapper 创建的子卷。
  • 重新创建 /.snapshots 挂载点并重新挂载 @.snapshots 子卷。

此时,配置已激活。如果您的 cron 守护程序正在运行,snapper 将拍摄 #自动时间线快照。如果您不使用 cron 守护程序,您将需要使用 systemd 服务和计时器。请参阅 #启用/禁用

另请参阅 snapper-configs(5)

拍摄快照

自动时间线快照

可以使用可配置数量的每小时、每日、每周、每月和每年快照来创建快照时间线。启用时间线后,默认情况下每小时创建一个快照。每天一次,快照会通过时间线清理算法进行清理。有关详细信息,请参阅 snapper-configs(5) 中的 TIMELINE_* 变量。

启用/禁用

如果您有 cron 守护程序,此功能应自动启动。要禁用它,请编辑与您不希望拥有此功能的子卷对应的配置文件,并设置

TIMELINE_CREATE="no"

如果您没有 cron 守护程序,则可以使用提供的 systemd 单元。启动启用 snapper-timeline.timer 以启动自动快照时间线。此外,启动启用 snapper-cleanup.timer 以定期清理旧快照。

注意: 如果您有 cron 守护程序并且还启用了 systemd 单元,这可能会导致创建重复的快照。如果您希望在使用 systemd 单元时禁用 cron 集成,一种可能的解决方案是不通过 pacman 的 NoExtract 配置选项安装 snapper 软件包的 cron 文件。请参阅 [2]

设置快照限制

默认设置将保留 10 个每小时快照、10 个每日快照、10 个每月快照和 10 个每年快照。您可能需要在配置中更改此设置,尤其是在繁忙的子卷(如 /)上。请参阅 #防止速度减慢

这是一个名为 config 的配置示例部分,仅包含 5 个每小时快照、7 个每日快照,没有每月和每年快照

/etc/snapper/configs/config
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="5"
TIMELINE_LIMIT_DAILY="7"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="0"
TIMELINE_LIMIT_YEARLY="0"

更改快照和清理频率

如果您正在使用提供的 systemd 计时器,您可以编辑它们以更改快照和清理频率。

例如,在编辑 snapper-timeline.timer 时,添加以下内容以使频率为每五分钟一次,而不是每小时一次

[Timer]
OnCalendar=
OnCalendar=*:0/5

编辑 snapper-cleanup.timer 时,您需要更改 OnUnitActiveSec。要使清理每小时发生一次而不是每天一次,请添加

[Timer]
OnUnitActiveSec=1h

请参阅 systemd/Timerssystemd#Drop-in 文件

手动快照

单次快照

默认情况下,snapper 拍摄的快照类型为single,与其他快照没有特殊关系。

要手动拍摄子卷的快照,请执行

# snapper -c config create --description desc

上述命令不使用任何清理算法,因此快照将永久存储,直到删除

要设置清理算法,请在 create 之后使用 -c 标志,并选择 numbertimelineprepostnumber 设置 snapper 定期删除已超过配置文件中设置数量的快照。例如,要创建一个使用 number 算法进行清理的快照,请执行

# snapper -c config create -c number

有关 timeline 快照的工作原理,请参阅 #自动时间线快照,有关 prepost 的工作原理,请参阅 #前/后 快照

前/后 快照

另一种类型的快照 - pre/post 快照 - 旨在成对创建,一个在重大更改之前,一个在重大更改之后(例如系统更新)。

如果重大更改是/可以通过单个命令调用,则可以使用 snapper create --command 来调用该命令并自动创建 pre/post 快照

# snapper -c config create --command cmd
提示: 要将任何 shell 命令包装在 pre/post 快照中,还可以考虑使用 snpAUR shell 脚本,它比 snapper 的原生 --command 选项提供更好的输出重定向。

或者,pre/post 快照可以手动创建。

首先创建一个 pre 快照

# snapper -c config create -t pre -p

记下新快照的编号(创建 post 快照时需要它)。

现在执行将修改文件系统的操作(*例如*,安装新程序、升级等)。

最后,创建 post 快照,将 N 替换为 pre 快照的编号

# snapper -c config create -t post --pre-number N

另请参阅 #在快照中包装 pacman 事务

启动时快照

要让 snapper 拍摄 root 配置的快照,请启用 snapper-boot.timer。(这些快照的类型为 single。)

管理快照

列出配置

要列出已创建的所有配置,请执行

# snapper list-configs

列出快照

要列出为给定配置 config 拍摄的快照,请执行

# snapper -c config list

恢复快照

当恢复快照时,文件可能会保持原样,原因可能是该文件未包含在快照中(例如,它位于另一个子卷上),或者因为过滤器配置排除了该文件。

过滤器配置

此文章或章节的事实准确性存在争议。

原因: /etc/mtab/proc/self/mounts 的符号链接,因此还原它对系统没有影响。(在 Talk:Snapper 中讨论)

某些文件保留系统的状态信息,例如 /etc/mtab。永远不应还原此类文件。arch linux 中的默认配置确保了这一点。为了帮助用户,snapper 允许用户忽略这些文件。所有文件 /etc/snapper/filters/*.txt/usr/share/snapper/filters/*.txt 中的每一行都指定一个模式。当 snapper 计算两个快照之间的差异时,它会忽略与任何这些模式匹配的所有文件和目录。请注意,过滤器不会将文件或目录排除在快照之外。为此,请使用子卷或挂载点。

此文章或章节的事实准确性存在争议。

原因: 来自 SLES 文档的列表与 Arch Linux 有什么关系?(在 Talk:Snapper 中讨论)

另请参阅 SLES 文档中的从快照中排除的目录[死链接 2024-03-03 ⓘ]

使用默认布局恢复

此文章或章节的事实准确性存在争议。

原因: 什么是“默认布局”? 替代方案是什么?(在 Talk:Snapper 中讨论)

如果您正在使用 snapper 的默认布局,则每个快照都是子卷 .snapshots 目录中的子子卷,例如 @home

此文章或章节的事实准确性存在争议。

原因: 未用于 / 的子卷可以从系统本身恢复。只需以 root 身份登录,确保子卷未被使用,然后卸载它。(在 Talk:Snapper 中讨论)

要使用 snapper 的快照之一恢复 /home,请首先启动到 Arch Linux Live USB/CD。

使用 UUID 将 btrfs 根卷挂载到 /mnt

# mount -t btrfs -o subvol=/ /dev/disk/by-uuid/UUID_of_root_volume /mnt
# cd /mnt

此文章或章节的事实准确性存在争议。

原因: 这是为 Arch Linux Live USB/CD 编写的,其中没有 snapper 服务可以运行。(在 Talk:Snapper 中讨论)

如果 snapper 服务在正在运行的系统上运行,请停止它。检查是否有任何 snapper-unit.timers 正在运行,然后停止它们。

将损坏/旧的子卷移开,例如将 @home 移至 @home-backup

# mv @home @home-backup

找到您要恢复的快照的编号(每个快照都有一行,因此您可以轻松地将每个快照的编号和日期匹配起来)

# grep -r '<date>'  /mnt/@home-backup/.snapshots/*/info.xml
...
/mnt/@home-backup/.snapshots/number/info.xml:  <date>2021-07-26 22:00:00</date>
...
注意: info.xml 中记录的日期和时间的时区是 UTC,因此必须考虑与当地时间的时差。

记住 number

从快照编号 number 创建要恢复的新快照 @home

# btrfs subvolume snapshot @home-backup/.snapshots/number/snapshot @home

将目录 .snapshots 恢复到健康的子卷,例如 @home

# mv @home-backup/.snapshots @home/

如果在 fstab 中为 /home 挂载条目选项使用了 subvolid,而不是 /path/to/subvolume,请在 /mnt/@/etc/fstab 文件中将 subvolid 更改为可以使用 btrfs subvolume list /mnt | grep @home$ 找到的新 subvolid。(假设 @ 是系统中挂载为 / 的子卷)。

重启。

检查您的系统是否按预期工作,如果需要,删除旧的/损坏的快照(例如 @home-backup)。您应该检查它是否包含可以恢复的有用数据。

删除快照

要删除快照编号 N,请执行

# snapper -c config delete N

可以一次删除多个快照。例如,要删除根配置的快照 65 和 70,请执行

# snapper -c root delete 65 70

要删除一系列快照,在此示例中,删除根配置的快照 65 和 70 之间的快照,请执行

# snapper -c root delete 65-70

要立即释放快照使用的空间,请使用 --sync

# snapper -c root delete --sync 65

要删除配置的所有快照、.snapshots 子卷和 snapper 配置文件

# snapper -c config delete-config 
注意: 删除 pre 快照时,应始终删除其对应的 post 快照,反之亦然。

非 root 用户访问

每个配置都是使用 root 用户创建的,默认情况下,只有 root 可以查看和访问它。

要能够为特定用户列出给定配置的快照,只需更改 /etc/snapper/configs/config 文件中 ALLOW_USERS 的值。现在您应该能够以普通用户身份运行 snapper -c config list

最终,您希望能够使用用户浏览 .snapshots 目录,但此目录的所有者必须保持 root。因此,您应该将组所有者更改为包含您感兴趣的用户的组,例如 users

# chmod a+rx .snapshots
# chown :users .snapshots

技巧和窍门

在快照中包装 pacman 事务

有一些软件包用于在 pacman 事务时自动创建快照

https://github.com/wesbarnett/snap-pac || snap-pac
  • grub-btrfs — 包括一个守护程序 (grub-btrfsd),可以通过 systemctl 启用该守护程序来查找新快照并自动将其包含在 GRUB 菜单中。
https://github.com/Antynea/grub-btrfs || grub-btrfs
https://github.com/maximbaz/snap-pac-grub || snap-pac-grubAUR
  • refind-btrfs — 在 snap-pac 制作快照后,将条目添加到 rEFInd
https://github.com/Venom1991/refind-btrfs || refind-btrfsAUR
  • snp — 将任何 shell 命令包装在 snapper pre-post 快照中(例如 snp pacman -Syu),比 snapper 的原生 --command 选项具有更好的输出(请参阅 #前/后 快照)。
https://gist.github.com/erikw/5229436 || snpAUR
  • limine-snapper-sync — 在 snap-pac 制作快照后,将 snapper 条目添加到 Limine 引导加载程序。
https://gitlab.com/Zesko/limine-snapper-sync || limine-snapper-syncAUR (有关详细信息,请参阅 Limine#Snapper 快照集成(用于 Btrfs)。)

启动到只读快照

依赖 grub-btrfssnap-pac-grubAURlimine-snapper-syncAUR 的用户应注意,默认情况下,Snapper 的快照是只读的,并且启动到只读快照存在一些固有的困难。许多服务(例如桌面管理器)都需要可写的 /var 目录,并且从只读快照启动时将无法启动。

为了解决这个问题,您可以使快照可写,或者使用开发人员批准的 overlayfs 启动快照的方法,使快照的行为类似于 Live CD 环境。

注意: 您对该快照中的文件所做的任何更改都不会保存,因为文件系统仅存在于 RAM 中。

使用 overlayfs 启动快照

  • 确保您的系统上安装了 grub-btrfs
  • grub-btrfs-overlayfs 添加到 /etc/mkinitcpio.confHOOKS 数组的末尾。例如
    HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems fsck grub-btrfs-overlayfs)
    注意: 因为 grub-btrfs-overlayfs 仅提供 运行时钩子,而没有 systemd 单元,所以它与基于 systemd 的 initramfs 兼容。请确保您使用基于 Busybox 的 initramfs。有关更多详细信息,请参阅 此 GitHub 问题
  • 重新生成 initramfs.

进一步阅读

提示: 或者,您可以使用 Limine 引导加载程序启动到快照。Snapper 和 Limine 之间的集成由 limine-snapper-syncAUR 提供,有关详细信息,请参阅 Limine#Snapper 快照集成(用于 Btrfs)

在 pacman 事务中备份非 Btrfs 启动分区

如果您的 /boot 分区位于非 Btrfs 文件系统(例如 ESP)上,则您无法使用它进行 snapper 备份。请参阅 系统备份#快照和 /boot 分区,以在内核更新时使用钩子自动将启动分区复制到 Btrfs 根目录。这也与 snap-pac 配合良好。

增量备份到外部驱动器

一些工具可以使用 snapper 来自动化备份。请参阅 Btrfs#增量备份到外部驱动器

建议的文件系统布局

注意: 以下布局旨在与 snapper rollback 一起使用,而是旨在缓解 #将 / 恢复到之前的快照 的固有问题。请参阅此论坛帖子

这是一个建议的文件系统布局,用于轻松地将挂载在根目录的子卷 @ 恢复到之前的快照

文件系统布局
子卷 挂载点
@ /
@home /home
@snapshots /.snapshots
@var_log /var/log
subvolid=5
  |
  ├── @ -|
  |     contained directories:
  |       ├── /usr
  |       ├── /bin
  |       ├── /.snapshots
  |       ├── ...
  |
  ├── @home
  ├── @snapshots
  ├── @var_log
  └── @...

子卷 @... 挂载到任何其他应具有自己的子卷的目录。

注意
  • 拍摄 @(挂载在根目录 /)的快照时,其他子卷不包含在快照中。即使子卷嵌套在 @ 下,@ 的快照也不会包含它。为您要保留快照的 @ 以外的其他子卷创建 snapper 配置。
  • 由于 Btrfs 限制,快照卷不能包含 交换文件。将交换文件放在另一个子卷上,或创建 交换分区

如果您要将系统恢复到 @ 的先前快照,则这些其他子卷将保持不受影响。例如,这允许您将 @ 恢复到之前的快照,同时保持您的 /home 不变,因为挂载在 /home 的子卷。

此布局允许 snapper 实用程序定期拍摄 / 的快照,同时使其易于在 / 变得无法启动时从 Arch Live CD 恢复 /

在这种情况下,在初始设置之后,snapper 不需要更改,并且将按预期工作。

提示
  • 考虑为其他目录创建子卷,这些目录包含您不想包含在 @ 子卷的快照和回滚中的数据,例如 /var/cache/var/spool/var/tmp/var/lib/machines (systemd-nspawn)、/var/lib/docker (Docker)、/var/lib/postgres (PostgreSQL) 以及 /var/lib/ 下的其他数据目录。是否要遵循扁平布局或创建嵌套子卷取决于您。另一方面,/var/lib/pacman 中的 pacman 数据库必须保留在根子卷 (@) 上。
  • 您可以在 @home 和任何其他子卷上运行 Snapper,以获得数据单独的快照和回滚功能。

snapper 和挂载点的配置

假定子卷 @ 挂载在根目录 /。还假定 /.snapshots 挂载并且作为文件夹存在,这可以通过以下命令确保

# umount /.snapshots
# rm -r /.snapshots

然后创建一个新的配置用于 /。Snapper create-config 会自动创建一个子卷 .snapshots,以根子卷 @ 作为其父级,这对于建议的文件系统布局不是必需的,可以删除。

# btrfs subvolume delete /.snapshots

删除子卷后,重新创建目录 /.snapshots

# mkdir /.snapshots

现在挂载 @snapshots/.snapshots。例如,对于位于 /dev/sda1 上的文件系统

# mount -o subvol=@snapshots /dev/sda1 /.snapshots

要使此挂载永久生效,请在 fstab 中添加一个条目。

或者,如果您有现有的 fstab 条目,请重新挂载快照子卷

# mount -a

给文件夹 750 权限

这将使 snapper 创建的所有快照都存储在 @ 子卷之外,以便可以随时轻松替换 @ 而不会丢失 snapper 快照。

将 / 恢复到之前的快照

要使用 snapper 的快照之一恢复 /,请首先启动到 Arch Linux Live USB/CD。

挂载顶层子卷 (subvolid=5)。也就是说,省略任何 subvolidsubvol 挂载标志。

找到您要恢复的快照的编号

# grep -r '<date>' /mnt/@snapshots/*/info.xml

输出应如下所示,每个快照都有一行,因此您可以轻松地将每个快照的编号和日期匹配起来。

/mnt/@snapshots/number/info.xml:  <date>2021-07-26 22:00:00</date>
注意: info.xml 中记录的日期和时间的时区是 UTC,因此必须考虑与当地时间的时差。

记住 number

现在,将 @ 移动到另一个位置(例如 /@.broken)以保存当前系统的副本。或者,只需使用 btrfs subvolume delete /mnt/@ 删除 @

创建 snapper 拍摄的只读快照的读写快照

# btrfs subvolume snapshot /mnt/@snapshots/number/snapshot /mnt/@

其中 number 是您要恢复的 snapper 快照的编号。

如果在 fstab 中为 / 挂载条目选项使用了 subvolid,而不是 /path/to/subvolume,请在 /mnt/@/etc/fstab 文件中将 subvolid 更改为可以使用 btrfs subvolume list /mnt | grep @$ 找到的新 subvolid。如果引导加载程序配置(例如 refind_linux.conf)包含 subvolid,也请更改它。

最后,卸载顶层子卷 (ID=5),然后挂载 @/mnt,并将您的 ESP 或启动分区挂载到适当的挂载点。切换根目录到您恢复的快照,以便重新生成您的 initramfs 镜像

您的 / 现在已恢复到之前的快照。现在只需重新启动即可。

提示: 您还可以使用为此布局制作的自动回滚工具:snapper-rollbackAUR。编辑 /etc/snapper-rollback.conf 中的配置文件以匹配您的系统。

将其他子卷恢复到之前的快照

请参阅 #恢复快照

从快照中删除文件

如果您想从过去的快照中删除特定文件或文件夹,而无需删除快照本身,snappersAUR 是一个脚本,它将此功能添加到 Snapper。此脚本还可用于以 Snapper 当前不支持的多种其他方式操作过去的快照。

如果您想在不使用额外脚本的情况下删除文件,您只需要使您的快照子卷可读写,您可以使用以下命令执行此操作

# btrfs property set /path/to/.snapshots/<snapshot_num>/snapshot ro false

验证 ro=false

# btrfs property get /path/to/.snapshots/<snapshot_num>/snapshot
ro=false

您现在可以像往常一样修改 /path/to/.snapshots/<snapshot_num>/snapshot 中的文件。您可以使用 shell 循环来批量处理快照。

防止速度减慢

在繁忙的文件系统(如 /)上为较长时间范围保留大量快照可能会导致严重的速度减慢,因为随着时间的推移会发生许多系统更新。您可以通过以下方式防止这种情况:

  • 创建不值得快照的项目的子卷,例如 /var/cache/pacman/pkg/var/abs/var/tmp/srv
  • 当使用 #自动时间线快照 时,编辑每小时/每天/每月/每年的快照的默认设置。

updatedb

默认情况下,updatedb(参见 locate)也会索引 snapper 创建的 .snapshots 目录,如果您有很多快照,这可能会导致严重的速度减慢和过多的内存使用。您可以通过编辑以下内容来阻止 updatedb 索引它:

/etc/updatedb.conf
PRUNENAMES = ".snapshots"

禁用配额组

有报告称,配额组会导致明显的减速,例如,如果 snapper ls 需要几分钟才能返回结果,则可能是由配额组引起的。请参阅 [3]

要确定是否启用了配额组,请使用以下命令

# btrfs qgroup show /

然后可以使用以下命令禁用配额组

# btrfs quota disable /

计算快照数量

如果禁用配额组没有帮助减速,则计算快照数量可能会有所帮助,这可以使用以下命令完成:

# btrfs subvolume list -s / | wc -l

为用户数据和日志创建子卷

建议将目录存储在它们自己的子卷上,而不是根子卷 / 上,如果它们包含用户数据(例如电子邮件)或日志。这样,如果还原 / 的快照,用户数据和日志也不会恢复到之前的状态。可以为用户数据维护单独的时间线快照。不建议为 /var/log 中的日志创建快照。这使其更易于进行故障排除。

也可以在使用 #过滤器配置 还原期间跳过目录。请参阅 SLES 文档,了解跳过某些路径的示例和原因

基于磁盘使用情况的清理

此文章或章节需要扩充。

原因: 请参阅 [4] 以获取想法。(在 Talk:Snapper 中讨论)

故障排除

Snapper 日志

Snapper 将所有活动写入 /var/log/snapper.log - 如果您认为出现问题,请首先检查此文件。

如果您在使用每小时/每天/每周快照时遇到问题,到目前为止最常见的原因是 cronie 服务(或您正在使用的任何 cron 守护程序)未运行。

IO 错误

如果您在尝试创建快照时收到“IO 错误”,请确保与您尝试快照的子卷关联的 .snapshots 目录本身是一个子卷。

另一个可能的原因是 .snapshots 目录的所有者不是 root(您将在 /var/log/snapper.log 中找到 Btrfs.cc(openInfosDir):219 - .snapshots must have owner root)。

孤立快照导致磁盘空间浪费

快照可能会“丢失”,它们仍然存在于磁盘上,但 snapper 不会跟踪它们。这可能会导致大量浪费的、无法解释的磁盘空间。要检查这一点,请比较以下输出:

# snapper -c <config> list

# btrfs subvolume list -o <parent subvolume>/.snapshots 

第二个列表中存在但第一个列表中不存在的任何子卷都是孤立的,可以手动 删除

另请参阅