为什么要用Btrfs和Snapper
先简单介绍一下Btrfs和Snapper
Btrfs是一种现代化的Linux文件系统,支持写时复制(COW),其设计目标是提供高级功能、高可靠性、可扩展性和易于管理,它由Oracle于2007年发起开发,现已用于SUSE、Fedora等发行版
Snapper是一个由openSUSE的工程师Arvin Schnell开发的一款用于管理Btrfs子卷和LVM卷的快照管理工具,它可以用于创建和比较快照、在快照之间进行回滚,并支持自动化生成快照等功能
Btrfs的一项非常重要的特性是它的快照和子卷,Snapper可以基于Btrfs快照和子卷功能来进行自动化快照管理,以更好的保护数据。Btrfs的快照基于其写时复制(COW)的机制,在初始创建时几乎不占用额外空间,仅记录与原始文件系统相同的指针。只有当数据发生更改时,快照才会存储差异数据,从而节省存储空间,这也为Snapper提供了高效的底层支持
所以,Snapper结合Btrfs的快照功能,可以带来非常强大的数据保护和恢复机制,无论是系统更新、误删文件,还是数据损坏,都可以通过Snapper快速回滚到之前的快照状态,可以很大程度上减少数据丢失风险
安装Snapper
注:本文在安装了Btrfs文件系统的Archlinux系统环境下撰写,所以需要提前安装好这两部分环境
先检查一下是否可以执行btrfs
命令,如果无法执行命令,则需要先执行下面命令安装btrfs-progs
包
sudo pacman -S btrfs-progs
然后安装Snapper工具相关的包
sudo pacman -S snapper snap-pac grub-btrfs inotify-tools # 其中inotify-tools是使用grub-btrfs所必须的
需要注意,上面我们安装了grub-btrfs
用于从Grub中引导进入快照,从而可以在系统崩溃无法登录的时候从特定快照状态启动系统来进行实现系统回滚,而根据Archwiki中的内容:
“在默认状态下,Snapper创建的快照是只读的,而在启动到只读快照时会有一些困难。许多服务,例如显示管理器,都需要一个可写的 /var
目录。而在启动到只读快照时,这些服务将无法正常工作。为了避免这个问题,可以使快照设为可写,或者使用overlayfs启动到快照中,这也是开发者认可的方法。”
因此,我们这里使用overlayfs启动快照,也就是需要添加grub-btrfs-overlayfs
到/etc/mkinitcpio.conf
文件中HOOKS
部分的末尾如下:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems fsck grub-btrfs-overlayfs)
添加后执行下面命令用于重新生成initramfs
sudo mkinitcpio -P
接下来安装btrfs-assistant
,这是一个Btrfs的GUI快照管理工具
sudo pacman -S btrfs-assistant
Snapper配置介绍
Snapper允许为每个Btrfs子卷创建单独的配置文件,从而实现对不同子卷的快照管理隔离,但Snapper安装后不会自动为Btrfs子卷创建配置,因此需要我们自己手动创建
首先可以执行下面命令查看一下当前已有的子卷配置,如果是刚安装的话目前应该不会显示任何配置
sudo snapper list-configs
由于我的Btrfs创建了/
和/home
两个子卷,所以我需要为这两个子卷分别创建配置如下
sudo snapper -c root create-config / # 为/子卷创建配置,并通过-c参数制定配置名
sudo snapper -c home create-config /home # # 为/home子卷创建配置,并通过-c参数制定配置名
这样我们就创建好了root
和home
两个配置,创建好的配置文件会保存在/etc/snapper/configs/
目录中,可以通过下面这些指令查看配置
sudo snapper list-configs # 列出当前已有的子卷配置
ls /etc/snapper/configs/ # 查看配置文件所在位置
sudo cat /etc/snapper/configs/root # 检查root配置文件的内容
sudo cat /etc/snapper/configs/home # 检查home配置文件的内容
sudo snapper -c root get-config # 用snapper命令查看root配置
sudo snapper -c home get-config # 用snapper命令查看home配置
注:-c参数用于指定要操作的子卷的配置名,如果要使用snapper命令对root配置进行操作,可以省略后面的-c root参数
由于用snapper
命令管理快照默认需要root
权限,如果想让我们当前用户不用sudo
就能使用snapper
命令,需要将配置文件中的ALLOW_USERS
参数设为我们的当前用户名,这里我们同时将SYNC_ACL
参数设为yes
来启用Snapper的访问控制列表(ACL)同步功能,以确保快照目录的权限与配置文件中指定的用户或组权限保持一致。可以直接打开/etc/snapper/configs/root
和/etc/snapper/configs/home
这两个配置文件进行修改,也可以执行下面命令修改
sudo snapper -c root set-config ALLOW_USERS="$USER" SYNC_ACL=yes
sudo snapper -c home set-config ALLOW_USERS="$USER" SYNC_ACL=yes
然后我们可以执行下面命令检查修改结果(可以发现我们不用sudo
就可以执行啦)
snapper -c root get-config
snapper -c home get-config
对其他配置内容我还适当进行了一些调整,具体如下,仅供参考
~ snapper get-config
Key │ Value
─────────────────────────┼──────────
ALLOW_GROUPS │
ALLOW_USERS │ cheerroad
BACKGROUND_COMPARISON │ yes
EMPTY_PRE_POST_CLEANUP │ yes
EMPTY_PRE_POST_MIN_AGE │ 3600
FREE_LIMIT │ 0.2
FSTYPE │ btrfs
NUMBER_CLEANUP │ yes
NUMBER_LIMIT │ 50
NUMBER_LIMIT_IMPORTANT │ 10
NUMBER_MIN_AGE │ 3600
QGROUP │
SPACE_LIMIT │ 0.5
SUBVOLUME │ /
SYNC_ACL │ yes
TIMELINE_CLEANUP │ yes
TIMELINE_CREATE │ yes
TIMELINE_LIMIT_DAILY │ 7
TIMELINE_LIMIT_HOURLY │ 5
TIMELINE_LIMIT_MONTHLY │ 0
TIMELINE_LIMIT_QUARTERLY │ 0
TIMELINE_LIMIT_WEEKLY │ 0
TIMELINE_LIMIT_YEARLY │ 0
TIMELINE_MIN_AGE │ 1800
最后启动下面三项必要的服务,这样必要的配置就完成啦
sudo systemctl enable --now grub-btrfsd.service # 自动更新Grub菜单以包含最新的Btrfs快照
sudo systemctl enable --now snapper-timeline.timer # 启用Snapper时间线快照定时器,定期为配置的子卷创建快照
sudo systemctl enable --now snapper-cleanup.timer # 启用Snapper清理定时器,定期删除过期的快照以释放存储空间
Snapper的使用说明
下面首先结合使用场景和例子介绍Snapper的使用,最后会对命令的使用方法进行总结
撤销包管理器(pacman)的安装操作
每次执行pacman
安装软件或更新系统等操作的时候会在/
子卷自动生成pre
和post
快照,分别表示安装前(pre
)和安装后(post
)
可以执行snapper ls
或snapper -c root ls
查看快照
然后记下快照的编号,假设1号快照表示执行pacman
安装操作前,2号快照表示执行pacman
安装操作后,可以用下面命令比较快照之间的差异
snapper -c root status 1..2 # status用于查看那些文件发生了改变,1..2表示从1号快照到2号快照
snapper -c root diff 1..2 # diff可以比较具体内容的变化
接下来我们撤销1号快照到2号快照的更改(撤销安装操作)
sudo snapper -c root undochange 1..2 # 注意,执行undochange必须要用sudo提权
只要快照存在,就还可以再恢复回去(恢复安装操作)
sudo snapper -c root undochange 2..1
撤销对文件的修改
假设我们对/etc/example.conf
文件了修改,我们只需要找一个修改文件前的任意快照比如2号快照用来撤销对文件的修改
可以先检查一下2号快照中的文件和现在的文件的差异,确认是我们想恢复的状态(这里只能用diff
命令不能用status
)
snapper -c root diff 2..0 /etc/example.conf # 0号快照代表系统此时此刻的状态
确认后就可以同样用undochange
来将/etc/example.conf
文件从当前状态恢复至2号快照(也就是修改前)的状态
sudo snapper -c root undochange 2..0 /etc/example.conf
手动创建pre和post快照并撤销快照间的修改
如果我们现在想对电脑做一系列操作可能导致文件系统大规模修改,我们可以在修改前后分别手动创建pre
和post
快照,这样即使搞崩了也可以恢复回去
首先我们对root
子卷和home
子卷分别创建pre
快照
snapper -c root create -t pre -c number -d -p <description> # create命令后面的-c参数用于指定快照的清理算法,如果不加的话,创建的快照将永久存在,不会被cleanup清理;-p参数可以用于输出创建快照的编号
snapper -c home create -t pre -c number -d -p <description>
然后我们可以对电脑做一系列操作
...
Do things
...
接下来创建post
快照,注意在创建的时候需要用--pre-number
参数指定pre
快照的编号
snapper -c root create -t post --pre-number 3 -c number -d <description>
snapper -c home create -t post --pre-number 1 -c number -d <description>
如果我们后面想撤销刚刚的一系列操作,只需要与前面类似执行undochange
即可
sudo snapper -c root undochange 3..8
sudo snapper -c home undochange 1..2
要想删除快照的话可以执行下面命令删除
snapper -c root delete 3-8
snapper -c home delete 1-2
创建标记为important的快照
important
只是一个在创建快照的时候指定的标记,在对子卷创建的配置文件中通常会有一个NUMBER_LIMIT_IMPORTANT
参数用来控制cleanup
算法要保留的带有important
标记的number
类型快照的数量
这个标记只需要在创建快照的时候在Userdata
(-u
参数)中指定important=yes
就好,例如:
snapper -c root create -t single -c number -u "important=yes" -d "This is an important snapshot"
执行命令前后自动创建pre和post快照
比如我们要执行某个命令可能导致一些变化,就可以让Snapper在执行前后自动创建快照,缺点是只允许指定一个子卷的配置,具体操作如下
snapper -c root create --command <cmd>
从Grub引导界面回滚到之前的快照
如果我们有一天把系统彻底搞崩了,无法正常引导进入系统,这时候我们可以先在Grub界面选择Archlinux Snapshots引导登录进某个快照
然后可以用两种方法进行回滚
第一种方法是通过GUI管理程序,还记得我们最前面有安装了一个叫btrfs-assistant
的快照管理工具吗?我们可以直接打开,从最上方菜单栏依次点击进入Snapper
- Browse/Restore
,选择想要回滚的快照,然后点击右上方的Restore
就完成啦,接下来关闭窗口直接reboot
就可以顺利登录了
第二种方法是登录后直接在终端执行下面命令进行Rollback
sudo snapper -c root rollback <snapshot_number>
sudo snapper -c home rollback <snapshot_number>
注:如果使用上面两种方法回滚后发现在登录的时候没有从快照引导登录的选项的话,可以在登录后执行下面命令以确保Grub界面显示快照选项
sudo grub-mkconfig -o /boot/grub/grub.cfg
总结
下面对Snapper的常用操作指令进行了总结和补充
# 1. 快照查看与信息
# 列出指定配置的所有快照
snapper -c <config> list
# 简写形式
snapper -c <config> ls
# 2. 快照比较
# 查看两个快照之间的文件状态变化
snapper -c <config> status <snapshot1>..<snapshot2>
# 查看两个快照间文件的详细差异
snapper -c <config> diff <snapshot1>..<snapshot2> [文件路径]
# 3. 快照创建
# 创建快照
snapper -c <config> create -t <type> -c <cleanup> -d <description> -p
# 参数说明:
# -t <type>:快照类型(single/pre/post)
# -c <cleanup>:清理算法(number/timeline)
# -d <description>:快照描述
# -p:打印创建的快照编号
# 创建pre快照
snapper -c <config> create -t pre -c <cleanup> -d <description> -p
# 创建post快照(需关联 pre 快照)
snapper -c <config> create -t post --pre-number <pre_snapshot> -c <cleanup> -d <description>
# 创建带有用户数据(UserData)的快照
snapper -c <config> create -t <type> -c <cleanup> -u "key=value" -d <description>
# 命令执行前后自动创建pre和post快照
snapper -c <config> create --command <cmd>
# 4. 快照撤销与回滚
# 撤销两个快照间的更改,文件路径可选
sudo snapper -c <config> undochange <snapshot1>..<snapshot2> [文件路径]
# 回滚到指定快照
sudo snapper -c <config> rollback <snapshot_number>
# 5. 快照删除
# 删除指定快照
snapper -c <config> delete <snapshot_number> # 单个删除
snapper -c <config> delete <start_number>-<end_number> # 范围删除
# 6. 快照cleanup
# 清理快照(根据清理算法删除不再需要的快照)
snapper -c <config> cleanup <cleanup>
# 参数说明:
# <cleanup>:number(按编号)、timeline(按时间)
# 7. 配置管理
# 查看 snapper 配置
snapper -c <config> get-config
# 修改 snapper 配置
sudo snapper -c <config> set-config <key>=<value>
# 创建新的 snapper 配置
sudo snapper --config <new_config> create-config <subvolume>
# 8. 全局选项
# 常用全局选项(适用于大多数命令):
# --verbose (-v):显示详细信息
# --quiet (-q):减少输出
补充
关于不同子卷快照的存放位置及快照占用
由于不同子卷的快照是独立的,通常存放在子卷目录下的.snapshots
目录下,例如根目录子卷(/
)子卷的快照存放在/.snapshots
,家目录(/home
)子卷的快照存放在/home/.snapshots
如果我们想查看一下快照占用了多少空间,用du
命令是无法显示实际占用的(如果执行sudo du -sch /.snapshots/*
会显示非常大的空间,并非实际占用)
而Btrfs提供了一个专门的工具btrfs filesystem du
可以区分文件的总大小(逻辑大小)和独占大小(实际占用空间),因此我们可以执行下面命令查看快照的实际占用
sudo btrfs filesystem du -s /.snapshots/*
Rollback和Undochange的区别
- undochange
undochange
命令用于撤销两个快照之间的特定更改,而不会影响文件系统的整体状态或后续更改。例如,如果你执行undochange 1..2
,Snapper会撤销从快照1到快照2之间的所有变化,但快照2生成之后所做的任何更改都会保留。这意味着,文件系统会被调整到类似于快照1的状态,但仍然保留快照2之后的修改。 - rollback
与undochange
不同,rollback
是一种非常彻底的操作,它会将文件系统完全恢复到某个快照的状态。例如,执行rollback 1
会让文件系统回到快照1的状态,并且快照1之后的所有更改(包括后续的快照,如快照2、快照3等)都将被丢弃。回滚后,Snapper 会创建一个新快照来记录回滚前的状态,以确保操作可追溯。
简单而言,undochange
仅仅是撤销两个快照之间的操作,而rollback
是完全恢复到某个快照