正确地将Ubuntu安装到Btrfs中
Btrfs是一个相对较新的文件系统,它提供了许多先进的功能,如CoW(写时文件复制)、快照、压缩、校验和等。然而,它在Ubuntu中的支持并不完善,因此在安装Ubuntu到Btrfs中时,需要注意一些细节。
为什么选择Btrfs而不是ZFS
Btrfs与ZFS的详细对比可以参考这篇文章
ZFS是另一个先进的文件系统,它提供了与Btrfs类似的功能,并且在某些场景下有更高的灵活性和性能。但是使用ZFS作为系统盘目前有以下问题:
- ZFS并不在Linux内核中,如果将系统安装至ZFS,必须手动通过模块的方式加载ZFS模块。若系统出现异常,如何在救援模式中访问zfs pool也是一个问题。而Btrfs是Linux内核的一部分,目前绝大多数的linux发行版都提供了开箱即用的Btrfs支持。
- ZFS的内存需求较高,可能会占用更多的系统资源。
- ZFS目前仅在Ubuntu Desktop 24.04安装中提供极为有限的实验性支持(必须清除整块硬盘进行安装), 在Ubuntu Server乃至其它发行版中很少提供官方支持。在安装Arch Linux时也必须对照专门的文档添加zfs特定的模块才可使用。而Btrfs已在openSUSE中作为默认文件系统多年,并且目前已被大多数Linux发行版支持。
因此我认为至少在现阶段,使用Btrfs作为系统盘是一个更好的选择。
安装Ubuntu到Btrfs中
这个过程与安装到其它文件系统并没有太大的区别,无论你在安装的是Ubuntu Desktop还是Ubuntu Server, 都可以按照正常的安装流程进行。唯一需要注意的是在安装过程中选择Btrfs作为文件系统。
将Btrfs下的Ubuntu系统转换为子卷格式
Ubuntu 24.04不再使用子卷格式来安装Ubuntu,而是将所有文件安装在根子卷中。这种安装方法将失去对系统不同文件分卷管理的很多优势,如无法单独对用户数据进行快照、无法单独对系统文件进行快照等。
你可以通过以下命令来确认当前btrfs卷中的子卷情况:
1 | sudo btrfs subvolume list / |
如果你的系统中只有一个根子卷,建议通过下面的方式将系统转换为子卷格式,以便于管理和备份。如果你的系统已经使用了子卷格式,可以跳过这一步。
在下面的步骤中,我们会创建以下子卷并将其挂载到对应目录:
子卷名称 | 挂载目录 | 用途 |
---|---|---|
@ | / | 系统根目录 |
@home | /home | 用户数据 |
@cache | /var/cache | apt等缓存 |
@log | /var/log | 日志 |
@swap | /swapfile | swap文件 |
@snapshots | /.snapshots | 根目录的快照 |
对于/tmp目录,我们将直接使用tmpfs进行挂载,根据此文章,使用tmpfs可以提高性能并减少对磁盘的写入。
以下操作会对系统所在的Btrfs卷进行修改,请确认你输入了正确的命令并谨慎操作。操作失误可能导致系统故障甚至数据丢失。
如果系统分区中有重要的业务数据,建议提前进行备份。可以使用umount取消挂载无关的卷,以减少操作风险。
建议准备任意发行版的LiveCD,以便在系统无法启动时进行救援。
以下操作需要重新安装grub(grub-install
)并更新grub配置(update-grub
),请确保你清楚grub所在的位置(Legacy中的引导设备或UEFI中的EFI分区)。
以下操作要求您具有一定的Linux与Btrfs基础知识,如编辑/etc/fstab
、挂载或取消挂载卷、进行grub-install
等操作。建议在开始前先完整阅读以下步骤,确保您理解每一步的含义。
以下方式参考了此文章
如果你的btrfs卷中存放了swap文件,需要先关闭swap并删除swap文件以便于对根目录进行快照:
使用
swapon --show
查看当前的swap文件,然后使用swapoff -a
关闭swap文件。删除swap文件,我们会在后续的步骤中重新创建swap文件(如果需要)。
1
2sudo swapoff -a
sudo rm /swap.img # Change the path to your swap file编辑
/etc/fstab
文件,删除或注释swap文件的挂载项。1
sudo vi /etc/fstab
对根目录进行快照:
1
sudo btrfs subvolume snapshot / /@
我们接下来的所有操作都会在这个快照上进行,以保证不会干扰到目前正在运行的系统。但是这也意味着从执行这个命令后根子卷的所有文件变更都不会保留到重启后的系统中。
创建所需的其它子卷,并将文件移动到对应的子卷中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14sudo btrfs subvolume create /@home
sudo mv /@/home/* /@home
sudo btrfs subvolume create /@cache
sudo mv /@/var/cache/* /@cache
sudo btrfs subvolume create /@log
sudo mv /@/var/log/* /@log
sudo btrfs subvolume create /@swap
sudo mkdir /@/swapfile # Create a directory for the mount point
sudo btrfs subvolume create /@snapshots
sudo mkdir /@/.snapshots # Create a directory for the mount point这里可以顺便清空tmp目录,我们稍后将使用tmpfs来挂载:
1
sudo rm -rf /@/tmp/*
编辑
/etc/fstab
,设置各个子卷的挂载点信息。1
sudo vi /@/etc/fstab
找到类似如下的根目录的挂载项(其中UUID为btrfs卷所在分区标识符):
1
/dev/disk/by-uuid/<UUID> / btrfs defaults 0 1
将其更改为:
1
/dev/disk/by-uuid/<UUID> / btrfs subvol=@,defaults 0 1
复制该行,并依次添加以下子卷的挂载项:
1
2
3
4
5/dev/disk/by-uuid/<UUID> /.snapshots btrfs subvol=@snapshots,defaults 0 1
/dev/disk/by-uuid/<UUID> /home btrfs subvol=@home,defaults 0 1
/dev/disk/by-uuid/<UUID> /swapfile btrfs subvol=@swap,defaults 0 1
/dev/disk/by-uuid/<UUID> /var/cache btrfs subvol=@cache,defaults 0 1
/dev/disk/by-uuid/<UUID> /var/log btrfs subvol=@log,defaults 0 1添加
/tmp
路径的挂载项:1
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
最后fstab文件应该类似如下(UUID为你的Btrfs分区对应UUID):
1
2
3
4
5
6
7
8
9
10
11/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b / btrfs subvol=@,defaults 0 1
/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b /.snapshots btrfs subvol=@snapshots,defaults 0 1
/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b /home btrfs subvol=@home,defaults 0 1
/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b /swapfile btrfs subvol=@swap,defaults 0 1
/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b /var/cache btrfs subvol=@cache,defaults 0 1
/dev/disk/by-uuid/26d85121-ee34-4266-8dcf-dc73292f7d2b /var/log btrfs subvol=@log,defaults 0 1
tmpfs /tmp tmpfs rw,nosuid,nodev,mode=1777 0 0 # Use tmpfs for tmp directory
# /boot/efi was on /dev/sdj1 during curtin installation
/dev/disk/by-uuid/29F8-F222 /boot/efi vfat defaults 0 1编辑grub菜单超时配置,以便于在启动时编辑grub菜单:
1
sudo vi /etc/default/grub
找到并修改下面选项:
1
2GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu更新grub配置:
1
sudo update-grub
重启系统。
1
sudo reboot
当grub菜单出现时,按下
e
键编辑grub启动项。找到类似如下的启动项:
找到
linux
开头的行,为其路径添加/@/
前缀:1
linux /@/boot/...
然后在后面为其添加
rootflags=subvol=@
参数,类似如下:1
ro rootflags=subvol=@ quiet splash
修改完成后的行应类似如下:
1
2linux /@/boot/vmlinuz-6.8.0-40-generic root=UUID=<UUID> ro rootflags=subvol=@ quiet splash # Ubuntu Desktop
linux /@/boot/vmlinuz-6.8.0-40-generic root=UUID=<UUID> ro rootflags=subvol=@ # Ubuntu Server接着修改initrd行,同样为其路径添加
/@/
前缀:1
initrd /@/boot/...
完成后按下
F10
开始引导。进入系统后,确认目前的根目录由
@
子卷挂载:1
mount | grep ' / '
输出应类似如下:
1
/dev/nvme0n1p1 on / type btrfs (...subvol=/@...)
如果输出中没有
subvol=@
,则说明根目录没有正确挂载,需要检查之前的步骤是否有错误。可以再次重启系统,按照步骤7中的方式编辑grub启动项。你可以使用
sudo btrfs subvolume list /
来查看当前的子卷情况,结果应类似如下:1
2
3
4
5
6ID 258 gen 4629 top level 5 path @
ID 259 gen 4616 top level 5 path @home
ID 261 gen 4475 top level 5 path @swap
ID 354 gen 4519 top level 5 path @cache
ID 355 gen 4546 top level 5 path @snapshots
ID 430 gen 4629 top level 5 path @log重新安装grub,来永久应用新的挂载方式:
对于UEFI引导方式:
1
2
3
4sudo grub-install --efi-directory=/boot/efi
sudo update-grub
reboot对于Legacy引导方式:
1
2sudo grub-install /dev/sdX # Change the device to your boot device
sudo update-grub清除迁移前的系统文件:
首先需要挂载btrfs根卷:
1
2
3
4
5sudo mkdir -p /mnt/sysdrv
sudo mount /dev/nvme0n1p1 /mnt/sysdrv # Change the device to your root device
cd /mnt/sysdrv
ls -la你应该可以在ls的结果中看到我们刚刚创建的子卷,同时也包含了迁移前的系统文件:
1
2
3
4
5
6
7
8'@'/
'@cache/'
'@home/'
...
bin/
boot/
usr/
...我们需要删除迁移前的系统目录,但是保留刚刚创建的所有子卷,在
bash
中运行以下命令:1
2
3
4
5
6
7shopt -s extglob # Enable extended globbing
sudo echo !(@*) # Make sure you are deleting the correct files
sudo rm -rf !(@*) # Perform the deletion
shopt -u extglob # Disable extended globbing请确保你已经正确挂载了根子卷,并且确认你要删除的文件是正确的。在echo的结果中确保没有删除不应删除的文件。
到这里为止,你的系统已经成功迁移到子卷格式下。
如有必要,重新创建swap文件:
1
2
3
4
5
6
7
8cd /swapfile
sudo touch swap.img
sudo chattr +C swap.img # Disable CoW on the swap file
sudo fallocate -l 8G swap.img # Change the size to your needs
sudo chmod 600 swap.img
sudo mkswap swap.img
sudo vi /etc/fstab编辑
/etc/fstab
文件,添加swap文件的挂载项:1
/swapfile/swap.img none swap sw 0 0
使用
swapon -a
命令启用swap文件:1
2sudo swapon -a
sudo swapon --show安装Snapper用于管理快照:
1
sudo apt install snapper
使用下面命令创建当前根目录的快照配置文件:
1
sudo snapper -c root create-config /
Snapper会自动在运行apt命令等操作时创建快照,你可以使用
sudo snapper list
来查看当前的快照列表。 也可以使用sudo snapper create
手动创建快照。关于Snapper的更多用法,建议参考Arch Wiki。