Snapper - Arch Linux 中文维基

跳转到内容

# Snapper

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 Snapper，最近一次同步于 2025-02-08，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- Btrfs
- mkinitcpio-btrfs

Snapper 是一个由 openSUSE 的 Arvin Schnell 开发的工具，用于管理 Btrfs 子卷和 LVM 精简配置(thin-provisioned)卷。它可以创建和比较快照，在快照间回滚，并支持自动按时间序列创建快照。

## 安装

安装 snapper包 包。或者安装开发版本 snapper-gitAUR。

此外，还可以安装 GUI 前端 snapper-gui-gitAUR、btrfs-assistant包 或 snapper-toolsAUR。

## 建立一个新的配置

在为 btrfs 子卷建立一个 snapper 配置前，这个子卷必须已经存在。否则，你应该在建立 snapper 配置前创建它。

要为位置为 `/path/to/subvolume` 的 btrfs 子卷创建一个新的 snapper 配置文件，并命名为 `config`：

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

这将会：

- 根据 `/usr/share/snapper/config-templates/default` 处的默认配置模板创建一个配置文件 `/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]。要让 Snapper 使用 `@.snapshots` 来创建备份，需要进行如下操作：

- 卸载 `@.snapshots` 子卷并删除已存在的挂载点。

- 创建 Snapper 配置。

- 删除 Snapper 创建的子卷。

- 重新创建 `/.snapshots` 挂载点，重新挂载 `@.snapshots` 子卷。

此时，配置文件已经激活。如果你的 cron 守护进程已经运行， snapper 将会使用 #自动按时创建快照。否则，你需要使用 systemd 单元文件和定时器。参阅 #启用/停用。

参阅 snapper-configs(5)。

## 创建快照

### 自动按时创建快照

一个快照时间线(timeline)由可配置数目的每小时/日/月/年快照组成。当自动按时创建启用时，默认每小时创建一个快照。每天由时间线清理算法清理多余快照。详情请参照 snapper-configs(5) 中的 `TIMELINE_*` 变量。

#### 启用/停用

如果你拥有一个 cron 守护进程，该特性应该已经自动启用。要停用，编辑你想禁用该特性的子卷对应配置文件为：

    TIMELINE_CREATE="no"

如果你没有 cron 守护进程，你可以使用提供的 systemd 单元文件。启动并启用 `snapper-timeline.timer` 来启用自动按时创建快照。另外，启用并启动 `snapper-cleanup.timer` 来定期清理老旧快照。

注意：如果你有一个 cron 守护进程并同时启用了 systemd 单元，这可能会导致重复创建快照。如果你希望使用 systemd 单元并禁用 cron 集成，一中可行的方法是使用 pacman 的 NoExtract 配置选项。参见[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/定时器和 Systemd#附加配置片段。

### 手动创建快照

#### Single 快照

默认情况下 snapper 创建 single 类型的快照，它们与其他快照没有特别关系。

要为一个子卷创建快照：

     # snapper -c config create --description desc

以上命令没有对应的清理算法，因此该快照将会一直存储直到删除它。

要设置一个清理算法，在 `create` 后使用 `-c` 选项，并在 `number`，`timeline`，`pre` 或 `post` 中选择一个参数。 `number` 使 snapper 定期清理超出配置文件中设置的数量限制的快照。例如，要创建一个使用 `number` 清理算法的快照：

     # snapper -c config create -c number

参阅 #自动按时创建快照查看 `timeline` 是如何工作的。参阅 #pre/post 快照查看 `pre` `post` 如何工作。

#### pre/post 快照

另一种快照类型是 pre/post 快照。两个快照会在进行重大更改时先后成对创建（例如进行系统更新时）。

如果这种重大更改是/可被单个命令调用，那么 `snapper create --command` 可以在调用这个命令的同时创建 pre/post 快照。

    # snapper -c config create --command cmd

提示：要在创建 pre/post 快照时执行任何 shell 命令，可以考虑使用 snpAUR 脚本。这个脚本相比 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` is a symlink to `/proc/self/mounts`, so reverting it has no effect on the system.（在 Talk:Snapper 中讨论）

部分文件保存着系统的状态信息，例如 `/etc/mtab`。这些文件不应该被还原。Arch Linux 提供的 Snapper 的默认配置已经排除了这些文件。Snapper 支持按照用户排除某些文件或文件夹。`/etc/snapper/filters/*.txt` 和 `/usr/share/snapper/filters/*.txt` 中的每行指定了要排除的项目。当 Snapper 计算快照之间的差别时，会排除这些文件。注意，这些文件仍会包含在快照中，如果不想让这些文件包含在快照中，使用单独的子卷或者挂载点。

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

原因： How is the list from SLES documentation relevant for Arch Linux?（在 Talk:Snapper 中讨论）

参见 SUSE 的文档Directories That Are Excluded from Snapshots[失效链接 2024-03-03 ⓘ]。

#### 还原快照

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

原因： What is the "default layout"? What is the alternative?（在 Talk:Snapper 中讨论）

如果你使用 Snapper 的默认布局，每个快照是在所指定子卷下的 `.snapshots` 目录的下层子卷，例如 `@home` 的快照位于 `@home/.snapshots`下。

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

原因： Subvolumes that are not used for `/` can be restored from the system itself. Just log in as root, make sure that the subvolume is not used, and unmount it.（在 Talk:Snapper 中讨论）

例如要将某个快照恢复到 `home`，首先启动到 Arch Linux 的 LiveCD。 使用UUID将 btrfs 的顶层子卷挂载到`/mnt`。

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

将目前的子卷移动到其他地方，例如将 `@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` 快照来创建新快照。

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

将 `.snapshots` 移回恢复完成的子卷下，例如`@home`。

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

注意：如果在 fstab中指定的是 `subvolid` 而不是子卷路径，则需要更改 `/mnt/@/etc/fstab` 中的 `subvolid`（假定把@子卷挂载到了`/`）。 可以使用 `btrfs subvolume list /mnt | grep @home$` 来查询新的 `subvolid`。

重新启动计算机。

检查计算机运行是否正常。这时可以删除在还原之前创建的快照了——例如`@home-backup`。在删除前记得检查是否有需要保留的数据。

### 删除快照

要删除序号为 `N` 的快照:

     # snapper -c config delete N

可以一次删除多个快照。例如，要删除 root 配置文件的 65 和 70 号快照：

     # snapper -c root delete 65 70

要同时删除多个连续的快照，例如删除 65 到 70 号所有快照：

    # snapper -c root delete 65-70

要立即释放快照占用的磁盘空间，使用 `--sync` 选项：

    # snapper -c root delete --sync 65

要删除一个 Snapper 配置和其所有快照，包括 `.snapshots` 子卷：

    # snapper -c config delete-config

注意：删除 pre 快照时, 你应该总是删除对应的 post 快照。反之亦然。

### 允许非 root 用户访问

所有配置文件都是由 root 用户创建的，默认情况下，也只有 root 用户可以查看并访问它们。

要让指定用户可以列出某一配置文件的快照，修改 `/etc/snapper/configs/config` 中的 `ALLOW_USERS` 项。现在你应该可以以普通用户权限运行 `snapper -c configlist`

最后，如果你想允许某一用户浏览 `.snapshots` 目录，但是该目录的拥有者必须为 root。因此，你应该修改包括该用户的组为组拥有者，以 `users` 为例：

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

## 提示与技巧

### 在进行 pacman 操作时创建快照

下列软件包可以依据 pacman 进行的事务自动创建快照。

- snap-pac — 使用 pacman 钩子使 pacman 自动使用 Snapper 创建#pre/post 快照。类似与 openSUSE 的 YaST 的行为。

  https://github.com/wesbarnett/snap-pac || snap-pac包

- grub-btrfs — 包含了一个名为 grub-btrfsd 的 systemd 单元。可自动查找快照并将其添加到 GRUB 菜单中。

  https://github.com/Antynea/grub-btrfs || grub-btrfs包

- snap-pac-grub — 在 snap-pac包 创建快照后自动使用 grub-btrfs包 更新 GRUB 启动项。同样使用pacman 钩子。

  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 命令以供创建 pre/post 快照（例如`snp pacman -Syu`）相比 Snapper 自身的 `--command` 选项能更好的处理输出重定向（参见 #pre/post 快照）。

  https://gist.github.com/erikw/5229436 || snpAUR

- limine-snapper-sync — 在 snap-pac包 创建快照后自动在 Limine 中创建启动项。（参见Limine#Snapper snapshot integration for Btrfs）

  https://gitlab.com/Zesko/limine-snapper-sync || limine-snapper-syncAUR

#### 启动到只读快照中

使用 grub-btrfs包、snap-pac-grubAUR或limine-snapper-syncAUR的用户应该注意：在默认状态下，Snapper 创建的快照是只读的。而在启动到只读快照时会有一些困难。许多服务，例如显示管理器，都需要一个可写的 `/var` 目录。在启动到只读快照时，这些服务将无法正常工作。

为了避免这个问题，可以使快照设为可写，或者使用 overlayfs 启动到快照中，这也是开发者认可的方法。这种情况下快照像是一个 Live CD 环境。

注意：任何对快照中文件的更改都不会被保存，因为文件系统只是存在于内存上。

要使用 overlayfs 启动快照：

- 确保 grub-btrfs包 已经安装。
- 添加 `grub-btrfs-overlayfs` 到 `/etc/mkinitcpio.conf` `HOOKS` 的末尾。例如：

      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 issue。

- 重新生成 initramfs。

进一步了解：

- grub-btrfs README （包含了使用 dracut包 而不是 mkinitcpio包 的配置方法）
- Github 上的讨论

提示：你可以使用 Limine 启动到快照中。Limine 和 Snaper 间的集成由 limine-snapper-syncAUR 提供。参见Limine#Snapper snapshot integration for Btrfs。

#### 在进行 pacman 事务时备份非 btrfs /boot 分区

如果你的 `/boot` 分区是在一个非 btrfs 文件系统上（例如一个 ESP 分区），Snapper 无法备份这些分区。 在系统备份#快照与_/boot_分区中提供了一个自动在内核更新时将 `/boot`复制到你的 btrfs 根目录下的方法。这种方法也能和 snap-pac包 一起使用。

### 增量备份到外部驱动器

一些工具可以使用 Snapper 进行自动备份。参见 Btrfs#增量备份到外置设备。

### 建议的文件系统布局

注意：下列布局不是为了与 `snapper rollback` 搭配使用。而是为了缓解#Restoring / to its previous snapshot 中的某些问题。参见 论坛帖子。

这是一种建议的文件系统布局，可以方便的将挂载到 `/` 的 `@` 子卷还原到之前的状态：

文件系统布局
子卷 | 挂载点
--- | ---
@ | /
@home | /home
@snapshots | /.snapshots
@var_log | /var/log

    subvolid=5
      |
      ├── @ -|
      |     contained directories:
      |       ├── /usr
      |       ├── /bin
      |       ├── /.snapshots
      |       ├── ...
      |
      ├── @home
      ├── @snapshots
      ├── @var_log
      └── @...

子卷`@...`应当挂载到任何应有自己子卷的目录。

注意：

- 当对 `@` 子卷（挂载到`/`）创建快照时，其余子卷的将不会被包含在快照中。即使这些子卷位于 `@` 之下（子卷不是递归包含的）。如果需要为其他子卷创建快照，需要单独为这些子卷创建 Snapper 配置。
- 由于Btrfs 的限制，需要创建快照的子卷中不能包含swap 文件。将 swap 文件放到另外的子卷或者使用 swap 分区。

如果你想将`@`子卷恢复到之前的状态，其他的子卷将不会被影响。例如，当你在将`@`恢复到之前的快照时，`/home`将不会受到影响，因为`/home`挂载到了单独的子卷下。

这个布局能使 Snapper 定期为 `/`创建快照，并能让在出现启动问题时更容易还原快照。

在这种情况下，进行初始设置之后，Snapper不需要更多配置。

提示：

- 考虑为其他不想包含在`@`快照中的目录创建子卷。例如 `/var/cache`, `/var/spool`, `/var/tmp`, `/var/lib/machines` (systemd-nspawn), `/var/lib/docker` (Docker), `/var/lib/postgres` (PostgreSQL)，或是其他 `/var/lib/` 下的目录。你可以使用类似上面的平行子卷结构，或是创建下层子卷。但是，pacman 数据库 `/var/lib/pacman` 必须位于挂载到`/`的子卷下。
- 你可以为`@home`或是其他子卷单独创建快照或者还原快照。

#### 配置 Snapper 和挂载点

假定`@`挂载到了`/`下，同时 `/.snapshots` 未被挂载，同时也不存在同名目录。可以使用如下命令确认：

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

接下来为`/`#建立一个新的配置。Snapper 会自动在`@`下创建 `.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 创建的快照储存在 `@` 之外。所以 `@` 被还原或替换时也不会丢失快照。

#### 还原到之前的快照

要将 `/` 还原到某个快照的状态，首先启动到 Arch Linux Live CD。

挂载顶层子卷（subvolid=5）。也就是说，不使用任何 `subvolid` 或 `subvol` 挂载参数。

找到想还原快照的序号：

    # 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` 替换为你想还原的快照序号。

注意：如果在 fstab中指定的是 `subvolid` 而不是子卷路径，则需要更改 `/mnt/@/etc/fstab` 中的 `subvolid`（假定把@子卷挂载到了`/`）。 可以使用 `btrfs subvolume list /mnt | grep @$` 来查询新的 `subvolid`。另外若在启动加载器中使用了 `subvolid`，也需要一并更改。例如 `refind_linux.conf`。

最后，卸载顶层子卷（subvolid=5），挂载`@`到`/mnt`以及 ESP分区。chroot到完成还原的根目录下，并重新生成 initramfs。

现在`/`已经恢复到了之前快照的状态。重新启动计算机。

提示：你也可以使用为这种布局设计的自动回滚工具：snapper-rollbackAUR。编辑 `/etc/snapper-rollback.conf` 来匹配系统的实际布局情况。

#### 还原其他子卷到之前的状态

参见#还原快照。

### 从快照中删除文件

若你想删除指定的文件或文件夹而不想删除整个快照，可以使用 snappersAUR 实现。这个脚本还可用于以 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`，阻止`.snapshots`索引该目录：

    /etc/updatedb.conf

    PRUNENAMES = ".snapshots"

#### 禁用配额

Btrfs 的配额功能（不是后来引入的“简单配额”（simple quota））可能会导致删除快照时占用大量 CPU 来维护配额信息。

要确定配额是否已启用，使用如下命令：

    # btrfs qgroup show /

可以使用如下命令禁用配额：

    # btrfs quota disable /

#### 计算快照数量

如果禁用配额没有减缓性能问题，那么计算快照数量可能会有用：

    # btrfs subvolume list -s / | wc -l

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

如果目录中包含用户数据（如电子邮件或日志），建议将其存储在自己的子卷而不是根子卷 `/` 中。这样，如果恢复 `/` 的快照，用户数据和日志不会受到影响。可以为用户数据使用单独的 timeline。不建议为 `/var/log` 创建日志快照。这可能会导致难以排除故障。

还可以使用#过滤配置在还原过程中跳过某些目录。有关跳过某些目录的示例和原因，请参阅 SLES 文档。

### 依据磁盘使用量清理快照

这篇文章的某些内容需要扩充。

原因：See [3] for ideas. (在 Talk:Snapper 中讨论)

## 疑难解答

### 日志

Snapper 将所有活动写入到 `/var/log/snapper.log` 中——在你认为出错时，首先检查该文件。

当你遇到关于每小时/每日/每周快照的问题时，最常见的原因是由于 cronie 服务（或者你使用的其他 cron 守护进程）没有运行。

### IO 错误

如果你在试图创建快照时遇到 'IO Error'，请确认你试图创建快照的子卷对应的 .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

第二个命令列出的子卷但未出现在第一个命令的输出中的都是未被 snapper 管理的快照。可以手动删除。

## 相关资源

- Snapper homepage
- openSUSE Snapper portal
- Btrfs homepage
- Linux.com: Snapper: SUSE's Ultimate Btrfs Snapshot Manager

分类：​

- 文件系统
- 包含失效链接的页面

隐藏分类：​

- 使用“模板:准确性”标记的页面或章节

Snapper
添加话题