Snapper 是一個由 openSUSE 的 Arvin Schnell 開發的工具,用於管理 Btrfs 子卷和 LVM 精簡配置(thin-provisioned)卷。它可以創建和比較快照,在快照間回滾,並支持自動按時間序列創建快照。
安裝
安裝 snapper包 包。或者安裝開發版本 snapper-gitAUR。
此外,還可以安裝 GUI 前端 snapper-gui-gitAUR、btrfs-assistantAUR 或 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 /
@.snapshots
子卷已經被掛載到 /.snapshots
,這會導致 snapper create-config
無法正常創建配置 [1]。要讓 Snapper 使用 @.snapshots
來創建備份,需要進行如下操作:
- 卸載
@.snapshots
子卷並刪除已存在的掛載點。
- 創建 Snapper 配置。
- 刪除 Snapper 創建的子卷。
- 重新創建
/.snapshots
掛載點,重新掛載@.snapshots
子卷。
此時,配置文件已經激活。如果你的 cron 守護進程已經運行, snapper 將會使用 #自動按時創建快照。否則,你需要使用 systemd 單元文件和定時器。參閱 #啟用/停用。
創建快照
自動按時創建快照
一個快照時間線(timeline)由可配置數目的每小時/日/月/年快照組成。當自動按時創建啟用時,默認每小時創建一個快照。每天由時間線清理算法清理多餘快照。詳情請參照 snapper-configs(5) 中的 TIMELINE_*
變量。
啟用/停用
如果你擁有一個 cron 守護進程,該特性應該已經自動啟用。要停用,編輯你想禁用該特性的子卷對應配置文件為:
TIMELINE_CREATE="no"
如果你沒有 cron 守護進程,你可以使用提供的 systemd 單元文件。啟動並啟用 snapper-timeline.timer
來啟用自動按時創建快照。另外,啟用並啟動 snapper-cleanup.timer
來定期清理老舊快照。
設置快照限制
默認配置將保留 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
--command
選項能更好的處理輸出重定向。pre/post快照也可以被手動創建。
首先創建一個pre快照:
# snapper -c config create -t pre -p
記下被創建快照的序號(在創建post快照時需要用到)。
然後進行想要進行的操作(比如安裝一個程序,或是進行升級等)。
最後創建post快照,將下文的 N
替換為pre快照的序號:
# snapper -c config create -t post --pre-number N
啟動時快照
要讓 snapper 為 root
配置文件創建一個快照,啟用 snapper-boot.timer
。通過這種方式創建的快照是 Single 快照。
管理快照
列出配置
列出所有你已經創建的配置:
# snapper list-configs
列出快照
要列出名為 config 的配置文件對應的快照:
# snapper -c config list
還原快照
在還原快照時,部分文件可能會保持原樣,原因可能是快照中不包含該文件(例如,該文件位於另一個子卷上),也可能是過濾配置排除了該文件。
過濾配置
部分文件保存著系統的狀態信息,例如 /etc/mtab
。這些文件不應該被還原。Arch Linux 提供的 Snapper 的默認配置已經排除了這些文件。Snapper 支持按照用戶排除某些文件或文件夾。/etc/snapper/filters/*.txt
和 /usr/share/snapper/filters/*.txt
中的每行指定了要排除的項目。當 Snapper 計算快照之間的差別時,會排除這些文件。注意,這些文件仍會包含在快照中,如果不想讓這些文件包含在快照中,使用單獨的子卷或者掛載點。
參見 SUSE 的文檔Directories That Are Excluded from Snapshots[失效連結 2024-03-03 ⓘ]。
還原快照
如果你使用 Snapper 的默認布局,每個快照是在所指定子卷下的 .snapshots
目錄的下層子卷,例如 @home
的快照位於 @home/.snapshots
下。
例如要將某個快照恢復到 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/
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
允許非 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 的行為。
- grub-btrfs — 包含了一個名為 grub-btrfsd 的 systemd 單元。可自動查找快照並將其添加到 GRUB 菜單中。
- snap-pac-grub — 在 snap-pac包 創建快照後自動使用 grub-btrfs包 更新 GRUB 啟動項。同樣使用pacman 鉤子。
-
snp — 包裝任何 shell 命令以供創建 pre/post 快照(例如
snp pacman -Syu
)相比 Snapper 自身的--command
選項能更好的處理輸出重定向(參見 #pre/post 快照)。
- limine-snapper-sync — 在 snap-pac包 創建快照後自動在 Limine 中創建啟動項。(參見Limine#Snapper snapshot integration for Btrfs)
啟動到只讀快照中
使用 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 README (包含了使用 dracut包 而不是 mkinitcpio包 的配置方法)
- Github 上的討論
在進行 pacman 事務時備份非 btrfs /boot 分區
如果你的 /boot
分區是在一個非 btrfs 文件系統上(例如一個 ESP 分區),Snapper 無法備份這些分區。
在系統備份#快照與_/boot_分區中提供了一個自動在內核更新時將 /boot
複製到你的 btrfs 根目錄下的方法。這種方法也能和 snap-pac包 一起使用。
增量備份到外部驅動器
一些工具可以使用 Snapper 進行自動備份。參見 Btrfs#增量備份到外置設備。
建議的文件系統布局
這是一種建議的文件系統布局,可以方便的將掛載到 /
的 @
子卷還原到之前的狀態:
子卷 | 掛載點 |
---|---|
@ | / |
@home | /home |
@snapshots | /.snapshots |
@var_log | /var/log |
subvolid=5 | ├── @ -| | contained directories: | ├── /usr | ├── /bin | ├── /.snapshots | ├── ... | ├── @home ├── @snapshots ├── @var_log └── @...
子卷@...
應當掛載到任何應有自己子卷的目錄。
如果你想將@
子卷恢復到之前的狀態,其他的子卷將不會被影響。例如,當你在將@
恢復到之前的快照時,/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
替換為你想還原的快照序號。
subvolid
而不是子卷路徑,則需要更改 /mnt/@/etc/fstab
中的 subvolid
(假定把@子卷掛載到了/
)。
可以使用 btrfs subvolume list /mnt | grep @$
來查詢新的 subvolid
。另外若在啟動加載器中使用了 subvolid
,也需要一併更改。例如 refind_linux.conf
。最後,卸載頂層子卷(subvolid=5),掛載@
到/mnt
以及 ESP分區。chroot到完成還原的根目錄下,並重新生成 initramfs。
現在/
已經恢復到了之前快照的狀態。重新啟動計算機。
/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 循環批量處理快照。
減緩性能影響
在/
這種繁忙的文件系統中,長時間保留大量快照會導致嚴重的性能影響。你可以通過以下方式減緩影響:
updatedb
默認情況下,updatedb
(參見locate)也會索引由 snapper 創建的 .snapshots
目錄,如果快照較多,這可能會導致運行速度嚴重的性能影響和大量內存占用。你可以編輯updatedb
,阻止.snapshots
索引該目錄:
/etc/updatedb.conf
PRUNENAMES = ".snapshots"
禁用配額
有報告稱,配額會導致運行速度明顯變慢,例如,snapper ls
需要數分鐘才能返回結果,這可能就是配額導致的。參見 [3]。
要確定配額是否已啟用,使用如下命令:
# btrfs qgroup show /
可以使用如下命令禁用配額:
# btrfs quota disable /
計算快照數量
如果禁用配額沒有減緩性能問題,那麼計算快照數量可能會有用:
# btrfs subvolume list -s / | wc -l
為用戶數據和日誌創建子卷
如果目錄中包含用戶數據(如電子郵件或日誌),建議將其存儲在自己的子卷而不是根子卷 /
中。這樣,如果恢復 /
的快照,用戶數據和日誌不會受到影響。可以為用戶數據使用單獨的 timeline。不建議為 /var/log
創建日誌快照。這可能會導致難以排除故障。
還可以使用#過濾配置在還原過程中跳過某些目錄。有關跳過某些目錄的示例和原因,請參閱 SLES 文檔。
依據磁碟使用量清理快照
疑難解答
日誌
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 管理的快照。可以手動刪除。