使用 Btrfs 快照方便升級 Fedora Linux 且易於回退
![](https://linuxstory.org/wp-content/uploads/2024/06/113654ba1kp126nzn6tpjv-800x400.jpg)
在 2018 年的一篇 早前的文章 中,我們介紹了在升級 Fedora Linux 前如何利用 LVM 複製根文件系統,以便在可能出現錯誤的情況下能有一個回退機制。然而如今,Fedora 工作站的默認安裝已經是 Btrfs 文件系統了。現在,你可以利用 Btrfs 快照來更簡便地創建一個可引導的回退系統。注意,本文不涉及會如何從其它文件系統轉換或遷移到 Btrfs 上。
確認根文件系統是否為 Btrfs
本示例採用的是 Pinebook aarch64 筆記本電腦。在開始前,務必確認你的根文件系統是否採用 Btrfs。要明確,不是所有的定製版或者鏡像文件默認都使用 Btrfs。
$ df -T
Filesystem Type 1K-blocks Used Available Use% Mounted on
devtmpfs devtmpfs 4096 0 4096 0% /dev
tmpfs tmpfs 998992 0 998992 0% /dev/shm
tmpfs tmpfs 399600 6360 393240 2% /run
/dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% /
tmpfs tmpfs 998996 24 998972 1% /tmp
tmpfs tmpfs 5242880 0 5242880 0% /var/lib/mock
/dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% /f34
/dev/mmcblk2p3 btrfs 56929280 39796116 15058348 73% /home
/dev/mmcblk2p2 ext4 996780 551888 376080 60% /boot
/dev/mmcblk2p1 vfat 194348 31648 162700 17% /boot/efi
tmpfs tmpfs 199796 100 199696 1% /run/user/1000
tmpfs tmpfs 199796 84 199712 1% /run/user/0
列出當前的 Btrfs 子卷
以上的示例輸出顯示掛載在 「根」(/
)的文件系統類型是 Btrfs。你會注意到,有三個掛載點顯示了相同的備份設備以及 已用 和 可用 的塊數。這是因為它們是從同一 Btrfs 文件系統掛載的不同部分(子卷)。比如,/f34
子卷是我去年創建的那個可引導快照。
默認的 Fedora Btrfs 安裝會創建一個 Btrfs 文件系統,並在其上分別掛載兩個子卷,root
和 home
,掛載路徑分別為 /
和 /home
。讓我們一起來看看我還添加了哪些其它的子卷:
$ sudo btrfs subvol list /
ID 272 gen 110428 top level 5 path root
ID 273 gen 110426 top level 5 path home
ID 300 gen 109923 top level 5 path f34
ID 301 gen 95852 top level 5 path home.22Jul26
ID 302 gen 95854 top level 5 path f36.22Jul26
在這裡,我們有一個來自最近一次系統升級的 f34
子卷,以及兩個只讀快照 home
和 f36
。要添加和刪除這些快照,最簡單的方法就是掛載 Btrfs 的根目錄。我會更新系統並創建當前 f36 root
子卷的新快照。如果你已經重命名了你的 root
子卷,我相信你知道該如何調整以下的示例以適應你的系統。
創建 Btrfs 的回退快照
$ sudo dnf update --refresh
...更新了很多部分(如果升級了內核還需要重啟)
$ sudo mkdir -p /mnt/root
$ sudo mount /dev/mmcblk2p3 /mnt/root
$ cd /mnt/root
$ ls
f34 f36.22Jul26 home home.22Jul26 root
$ sudo btrfs subvol snapshot root f36
Create a snapshot of 'root' in './f36'
因為 Btrfs 快照是以文件系統為基礎的,所以並不需要在創建快照之前進行 「同步」,正如我在 LVM 中建議的。要從新的子卷引導為回退,你需要使用你喜歡的編輯器編輯 /mnt/root/f36/etc/fstab
。如果你是剛入門的話,nano 就是一款十分簡單的文本編輯器,功能基本夠用。以下是我 fstab
文件中的一些行:
LABEL=PINE / btrfs subvol=root,compress=zstd:1 1 1
UUID=e31667fb-5b6f-48d9-aa90-f2fd6aa5f005 /boot ext4 defaults 1 2
UUID=75DB-5832 /boot/efi vfat umask=0077,shortname=winnt 0 2
LABEL=PINE /home btrfs subvol=home,compress=zstd:1 1 1
LABEL=SWAP swap swap discard=once 0 0
將 subvol=root
更改為 subvol=f36
。這個改動是作用在快照中的文件,而並非你實際運行中的 fstab
文件。你可以通過 diff /etc/fstab /mnt/root/f36/etc/fstab
對比它們的區別。在我的情況下,我還使用了 sudo btrfs subvol delete f34
來刪除我去年的 f34
快照。
測試 Btrfs 的回退快照
你現在可以進行回退的測試了。你可以使用 grubby 或在 /boot/loader/entries
中編輯一項來將 subvol=root
替換為 subvol=f36
。然而,為了初學者的安全起見,我們更建議你在啟動時編輯 GRUB 進行操作。你可以參考 關於 GRUB 的這篇文章 了解如何進入 GRUB 菜單。在你到達那裡後,按下 e
鍵編輯默認的內核啟動項。放心 —— 你所做的更改都只存在於內存中,如果你弄錯了,重啟電腦即可重新開始。就像編輯 fstab
文件一樣,找到 subvol=root
並將其更改為 subvol=f36
。然後,按 F10
或 Ctrl + X
來引導你修改過的項目。通過這些更改,你的系統應該能夠引導進入你的新快照。你可以查看 /etc/fstab
確保你正在引導至正確的子卷,或鍵入 mount | grep subvol
查看此時在 /
上掛載的子卷。
進行 Fedora Linux 的系統升級
如果你的回退功能沒問題,重啟並返回你的正常根文件系統(並像上面所述,進行確認)。然後,按照 維基頁面 上的指南進行標準的系統升級。提示:在運行 dnf system-upgrade reboot
之前,給 root
子卷創建另一個快照,你可以給它命名為 root.dl
。這樣,如果你發現硬碟空間不夠,你不必再下載五個 GB 的文件包。因為除了下載的包以外,所有的內容都將與 root
和 f36
共享,因此它不會佔用任何額外的空間。然後說到磁碟塊的共享問題……
因為在 root
子卷中的 f36
文件和 f36
子卷中的相同文件都使用的是相同的磁碟位置,所以在處理 Btrfs 報告的可用空間時,dnf system-upgrade
會感到困惑。因此在升級過程中從 root
子卷中刪除它們並不會真正釋放任何空間。如果你耗盡了所有空間,並且決定重啟電腦,那麼圖形用戶界面(GUI)將無法啟動。此時,你需要使用 Ctrl + Alt + F2
進入文本控制台並登錄,這將是你磨練命令行技能的好機會。如何清空空間或擴展根文件系統在這裡先不做討論(我的文件系統經常在一個 LVM 的卷上,可以被擴展)。通常,為升級保留超過 50% 的空閑空間是比較保險的。
恢復環節
如果不幸出現問題,你可以重啟電腦,並編輯 GRUB 條目以引導啟動回退快照。如果你是新手,一旦需要在磁碟上修改 GRUB 條目(這樣你就不需要每次啟動時都進行編輯),可能需要一些指導。刪除或重命名損壞的 root
子卷是非常直接的。你可以為 f36
子卷(或 root.dl
快照)創建一個快照,然後嘗試再一次進行系統升級。以下是在子卷 f36 上啟動到回退系統後重新開始的示例:
$ mount | grep subvol
$ sudo mount /dev/mmcblk2p3 /mnt/root
$ cd /mnt/root
$ sudo mv root root.failed
$ sudo btrfs subvol snapshot f36 root
Create a snapshot of 'f36' in './root'
Don't forget to edit /mnt/root/root/etc/fstab to change the subvol mounted on "/" to "root".
事實證明,新的 f38 版本的 kernel-6.2.11 在我的 Pinebook 上進行系統升級後並未成功啟動!(不過請不要擔心,ARM 只是 Fedora Linux 的可選 CPU 架構——在主流設備上,你很少會遭遇此類問題。)的確,我成功地按照前文所述,在啟動時編輯了 GRUB 條目並恢復到了 f36 的 kernel-6.2.10。現在,我繼續使用著 f38,但同時搭載了 f36 的 kernel-6.2.10。
更新:kernel-6.2.12 已經發布,且我已確認它在 Pinebook 上運行正常。
過期問題
隨著你不斷更新 f38 系統,它最終可能會希望刪除 /boot
下的最後一個 f36 內核。通常來說,這並不是問題,因為到那個時候,你已經完全熟悉 f38,而 f36
快照只是一個存檔。然而,如果你希望你的復刻版本(即 f36
的快照)能無限期地啟動,那麼你應當在 /boot
下保存一個能正常工作的 f36 內核。最簡單的方法是在 /etc/dnf/dnf.conf
文件中設置 installonly_limit=0
並手動移除舊的內核,這種方法既簡單又安全(儘管可能稍顯繁瑣)。
這裡還有一個更複雜的解決方案(不適合新手):運行 find /boot -name "*fc36*"
指令,列舉出所有在 f36
子卷快照中的內核及 GRUB 文件(這些文件並未包含在快照之內)。將這些文件備份至安全位置(例如我會掛載 f36
子卷,並將文件備份至其下的一個目錄)。當 f38 系統啟動後,對於每一個 f36 內核版本,都需使用 dnf
刪除特定版本的內核(例如,使用 dnf remove kernel-core-5.19.11-200.fc36
)。千萬不要刪除 f38 的內核!然後將你先前備份的 f36 內核恢復至 /boot
下。此時,f38 系統已經無法再識別 f36 的內核,因此也不會將其從 /boot
中刪除。
然而,使用此方法有一個缺點,那就是你可能會不小心刪除正在運行的 f38 內核。如果大家有更佳的解決辦法,歡迎在評論區分享。
展望未來
對於習慣於修改 GRUB 條目的用戶,他們可能會考慮創建一個命名為 f38
的快照子卷。將當前的 GRUB 條目進行修改,以便啟動到這個子卷,重啟後,在這個子卷中進行系統升級。此後,總是根據它所包含的 Fedora Linux 版本來命名根文件系統的子卷。但在本文中,我沒有採用這種作法,原因有兩點:
- 將當前活動的子卷命名為
root
,這是遵循 Fedora Linux 的默認設置。 - 堅持使用
root
作為當前子卷,這樣在進行正常的系統升級操作之外,並不需要任何永久性的更改。
正如本文所展示的,針對重大系統更改(如系統版本升級)可能引發問題時,只讀快照作為本地恢復點,非常有用。這些快照還可以通過 Btrfs 的 send
子命令,發送至遠程備份。(如果遠程備份設備已經包含了先前的備份數據,Btrfs 可以進行增量發送,僅傳輸發生變更的文件,這樣就能節省時間和空間。)如果你打算長期存檔這些快照,保持清晰不混淆且能明確恢復順序的關鍵,就是要使用一套一致的命名規則。關於如何使用 Btrfs 的 send
命令來創建備份的更多信息,你可以參考關於 Btrfs 快照備份 的文章。
(題圖:MJ/6aed1d19-f1dd-4935-ad6f-61f6a868f150)
via: https://fedoramagazine.org/make-use-of-btrfs-snapshots-to-upgrade-fedora-linux-with-easy-fallback/
作者:Stuart D Gathman 選題:lujun9972 譯者:ChatGPT 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive