使用 Btrfs 快照进行升级 Fedora 具有简单回退功能的 Linux

早在 2018 年,之前的一篇文章就演示了如何在升级前使用 LVM 克隆根文件系统 Fedora Linux 以便在不太可能出现问题的情况下进行回退。 今天,默认 Fedora 工作站安装使用 Btrfs。 现在您可以使用 Btrfs 快照来更轻松地创建可引导回退。 请注意,将系统从另一个文件系统转换或迁移到 Btrfs 不在本文的讨论范围之内。

检查根文件系统是否为 Btrfs

这 example 使用 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 子卷

以上 example 输出显示安装在“root”(“/”)上的文件系统是 Btrfs 类型。 请注意,三个挂载点显示相同的支持设备以及相同的 Used 和 Available 块。 这是因为它们是从单个 Btrfs 文件系统挂载的部分(子卷)。 /f34 子卷是我去年的可引导快照。

默认 Fedora Btrfs install 创建一个 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 根子卷的新快照。 如果您重命名了您的根子卷,那么您大概知道足以调整以下内容 example 相应地为您的系统。

创建 Btrfs 回退快照

$ sudo dnf update --refresh
... lots of stuff updated (reboot if kernel updated)
$ 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 进行比较。 就我而言,我还删除了去年的 f34 快照 sudo btrfs 子卷删除 f34。

测试 Btrfs 回退快照

现在您已准备好测试回退。 您可以使用 grubby 或编辑 /boot/loader/entries 中的条目以将 subvol=root 更改为 subvol=f36。 但是为了初学者的安全起见,我会让您在引导时编辑 GRUB 条目。 查看 GRUB 上的这篇文章,了解有关进入 GRUB 菜单的提示。 到达那里后,请按 电子 编辑默认内核条目的键。 别担心——您的更改仅在易失性内存中。 如果您搞砸了,请重新启动以重新开始。 就像使用 fstab 一样,找到 subvol=root 并将其更改为 subvol=f36。 按 F10 或者 控制键+X 启动修改后的条目。 通过这些更改,系统应该启动到您的新快照。 查看 /etc/fstab 以确保您从正确的子卷引导,或输入 mount | grep subvol 查看挂载在“/”上的子卷。

做 Fedora Linux系统升级

如果您的回退工作正常,请重新启动回到您的正常根文件系统(并按上述确认)。 然后继续进行上概述的标准系统升级 维基页面. 提示:在运行 dnf system-upgrade reboot 之前,为 root 创建另一个快照。 将其命名为类似 root.dl 的名称。 这样,如果您发现没有足够的可用空间,就不必再次下载 5 GB 的软件包。 快照不会占用任何额外空间,因为除下载的包外,所有包都与 root 和 f36 共享。 关于磁盘块的共享……

dnf 系统升级对 Btrfs 报告的可用空间感到困惑,因为根子卷中的 f36 文件使用与 f36 子卷中相同文件相同的磁盘位置。 因此,在升级过程中将它们从根子卷中移除实际上并不会释放任何空间。 如果空间不足并重新启动——图形用户界面 (GUI) 将不会启动。 使用 控制键+Alt+F2 登录文本控制台并练习您的命令行界面技能。 弄清楚要删除什么以释放空间或如何扩展根文件系统超出了本文的范围(我的通常位于 LVM 卷上并且可以扩展)。 有超过 50% 的免费升级是一个安全的选择。

恢复

如果出现问题,您可以重新启动并编辑 GRUB 条目以启动回退。 如果您是初学者,如果您最终需要更改磁盘上的 GRUB 条目(这样您就不必在每次启动时都进行编辑),那么您将需要一些帮助。 删除或重命名损坏的根子卷很简单。 拍摄 f36 子卷(或 root.dl 快照)以再次尝试系统升级过程。 这是一个 example 在 subvol 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 的新内核 6.2.11 无法在我的 Pinebook 上启动! (别担心,ARM 是一个可供选择的 CPU 架构 Fedora Linux — 在主流设备上这不太可能发生在你身上。)我确实能够通过在引导时编辑 kernel-6.2.10 的 GRUB 条目来引导回 f36,如上所述。 我现在再次使用 f38 — 但使用的是来自 f36 的 kernel-6.2.10。

更新: kernel-6.2.12 已发布,可在 Pinebook 上运行。

过期

当您更新 f38 系统时,它最终会想要从 /boot 中删除最后一个 f36 内核。 这通常不是问题,因为那时您已经适应了 f38,而 f36 快照只是一个存档。 如果您想无限期地保持您的 fork(f36 快照)可引导,您应该在 /boot 下保留一个工作的 f36 内核。 最简单的方法是在 /etc/dnf/dnf.conf 中设置 installonly_limit=0 并手动删除旧内核。 它既简单又安全(但很烦人)。

更复杂的解决方案概述(不适合初学者):运行 find /boot -name “*fc36*” 以列出 /boot 下(不在快照中)的 f36 子卷快照的所有内核和 GRUB 文件。 将它们复制到备份位置(我会挂载 f36 子卷并复制到那里的备份目录)。 从 f38 引导时,对于每个 f36 内核版本,使用 dnf 删除该特定内核版本(对于 example, dnf 删除 kernel-core-5.19.11-200.fc36)。 不要删除 f38 内核! 现在恢复您保存到 /boot 的 f36 内核。 f38 系统不再了解 f36 内核,并且不会将它们从 /boot 中删除。

该方法的问题是意外删除正在运行的 f38 内核的危险。 如果谁有更好的方法,请在评论中告诉我。

未来发展方向

那些熟悉修改 GRUB 条目的人可能会考虑创建一个名为 f38 的快照子卷,修改当前的 GRUB 条目以引导到该子卷,重新引导并在该子卷中运行系统升级。 然后始终在之后命名根文件系统的子卷 Fedora 它包含的 Linux 版本。 我没有为这篇文章这样做有两个原因。

  1. 命名当前活动的子卷根匹配 Fedora Linux 默认。
  2. 在当前的子卷中坚持使用 root 不需要在正常的系统升级过程之外进行任何永久更改。

正如本文所展示的,只读 snapsnots 可用作本地还原点,以防在进行重大系统更改(例如系统版本升级)时出现问题。 这些快照也可以使用 Btrfs 的发送子命令发送到远程备份。 (如果远程备份设备已经包含以前的备份,Btrfs 可以执行增量发送,只传输更改的文件以节省时间和空间。)如果您打算长期存档这些快照,关键是不要混淆哪些是which 和 what order 恢复它们是使用一致的命名约定。 有关使用 Btrfs 的发送命令创建备份的更多信息,请参阅有关用于备份的 Btrfs 快照的文章。