前言

在之前的如何在Gentoo上优雅的吃ZFS这篇文章中我们上了ZFS,但是没有给swap单独的一个分区,后来在使用中确实遇到了内存不够的情况。直接在系统里面丢swapfile是不合理的,最好是有个单独的分区给swap,所以还是要再来一次分区备份和恢复系统:)

我这里的思路是这样子:

  1. 创建ZFS池(建立在扩展的USB上)
  2. 创建快照
  3. 发送快照
  4. 重建分区和ZFS
  5. 恢复快照
  6. 更改fstab和Bootload信息
  7. 重启
  8. 定时任务

准备环境

这次需要准备物品如下:

  1. 主电脑(也就是我们目标备份的这台)
  2. 一个USB启动设备(需要有ZFS工具)
  3. 一个备份设备
  4. 另外一台电脑(推荐,有问题的时候可以通过这台电脑查询问题。)

创建备份ZFS池

首先进入livecd,查看设备:

1
fdisk -l

输出如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Disk /dev/nvme0n1: 1.86 TiB, 2048408248320 bytes, 4000797360 sectors
Disk model: KXG50PNV2T04 KIOXIA
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: AFD9539F-0A10-4184-9E73-20652BA3D677

Device          Start        End    Sectors  Size Type
/dev/nvme0n1p1   2048     264191     262144  128M Linux filesystem
/dev/nvme0n1p2 264192 4000797326 4000533135  1.9T Linux filesystem


Disk /dev/sda: 233.76 GiB, 251000193024 bytes, 490234752 sectors
Disk model: MAC3E
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/sdc: 57.81 GiB, 62075699200 bytes, 121241600 sectors
Disk model: DataTraveler 3.0
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 7EE1FFAC-4072-46B8-885E-A7EA3F9C70CF

Device       Start       End   Sectors  Size Type
/dev/sdc1       64   5735483   5735420  2.7G Microsoft basic data
/dev/sdc2  5735484   5745435      9952  4.9M EFI System
/dev/sdc3  5745436   5746035       600  300K Microsoft basic data
/dev/sdc4  5746688 121241536 115494849 55.1G Linux filesystem

这里的设备分别为:

物理位置说明
/dev/nvme0n1系统盘
/dev/sda备份盘
/dev/sdc启动盘

首先在备份盘上创建一个分区(分配所有空间到这个分区上):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fdisk /dev/sda
Welcome to fdisk (util-linux 2.36).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x108318f9.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (1-4, default 1):
First sector (2048-490234751, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-490234751, default 490234751):

Created a new partition 1 of type 'Linux' and of size 233.8 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

查看硬盘ID

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ls -l /dev/disk/by-id
total 0
lrwxrwxrwx 1 root root 13 Feb 27 14:37 nvme-KXG50PNV2T04_KIOXIA_Y9IS103FTHDM -> ../../nvme0n1
lrwxrwxrwx 1 root root 15 Feb 27 14:37 nvme-KXG50PNV2T04_KIOXIA_Y9IS103FTHDM-part1 -> ../../nvme0n1p1
lrwxrwxrwx 1 root root 15 Feb 27 14:37 nvme-KXG50PNV2T04_KIOXIA_Y9IS103FTHDM-part2 -> ../../nvme0n1p2
lrwxrwxrwx 1 root root 13 Feb 27 14:37 nvme-eui.000000000000001000080d0200600f01 -> ../../nvme0n1
lrwxrwxrwx 1 root root 15 Feb 27 14:37 nvme-eui.000000000000001000080d0200600f01-part1 -> ../../nvme0n1p1
lrwxrwxrwx 1 root root 15 Feb 27 14:37 nvme-eui.000000000000001000080d0200600f01-part2 -> ../../nvme0n1p2
lrwxrwxrwx 1 root root  9 Feb 27 14:53 usb-ACASIS_MAC3E_000000000001-0:0 -> ../../sda
lrwxrwxrwx 1 root root 10 Feb 27 14:53 usb-ACASIS_MAC3E_000000000001-0:0-part1 -> ../../sda1
lrwxrwxrwx 1 root root  9 Feb 27 14:37 usb-APPLE_SD_Card_Reader_000000000820-0:0 -> ../../sdb
lrwxrwxrwx 1 root root  9 Feb 27 14:37 usb-Kingston_DataTraveler_3.0_60A44C3D7ECDBF1089740049-0:0 -> ../../sdc
lrwxrwxrwx 1 root root 10 Feb 27 14:37 usb-Kingston_DataTraveler_3.0_60A44C3D7ECDBF1089740049-0:0-part1 -> ../../sdc1
lrwxrwxrwx 1 root root 10 Feb 27 14:37 usb-Kingston_DataTraveler_3.0_60A44C3D7ECDBF1089740049-0:0-part2 -> ../../sdc2
lrwxrwxrwx 1 root root 10 Feb 27 14:37 usb-Kingston_DataTraveler_3.0_60A44C3D7ECDBF1089740049-0:0-part3 -> ../../sdc3
lrwxrwxrwx 1 root root 10 Feb 27 14:37 usb-Kingston_DataTraveler_3.0_60A44C3D7ECDBF1089740049-0:0-part4 -> ../../sdc4

usb-ACASIS_MAC3E_000000000001-0:0-part1这里就是我们所需要的硬盘ID,我们使用这个来创建备份池子:

1
zpool create -f -o ashift=12 -o cachefile=/etc/zfs/zpool.cache -O compression=lz4 -O xattr=sa -O relatime=on -O acltype=posixacl -O dedup=off   -m none -R /mnt/backup backup  /dev/disk/by-id/usb-ACASIS_MAC3E_000000000001-0:0-part1

创建快照

首先导入原来的zpool

1
zpool import -f rock

给之前的系统创建一个快照:

1
sudo zfs snapshot rock/os/gentoo@2021-02-27-0000-01-install

查看

1
2
zfs list -r -t snapshot -o name,creation rock/os/gentoo
rock/os/gentoo@2021-02-27-0000-01-install  Sat Feb 27 14:16 2021

发送快照

我们需要打开原来的rock/os/gentoo数据集

但是首先要设置一下挂载点:

1
zfs set mountpoint=/mnt/gentoo rock/os/gentoo

打开rock/os/gentoo数据集

1
zfs mount -l -a

发送快照到backup/os/gentoo

1
zfs send rock/os/gentoo@2021-02-27-0000-01-install |  zfs recv backup/2021-02-27-0000-01-backup

这个会花很长的时间,取决于你使用的接口速度,可以通过这条命令查看io情况:

1
zpool iostat 2 

这条命令是查看所有的zpoolio情况,2秒刷新一次。

创建分区

当备份完成之后我们要重建分区,这里首先把原来的分区卸载然后干掉:

1
2
zfs unmount rock/os/gentoo
zpool destroy rock

备份/boot分区的内容

设置挂载点

1
zfs set mountpoint=/mnt/backup backup/2021-02-27-0000-01-backup

备份

1
2
3
mkdir -pv /mnt/boot
mount -v /dev/nvme0n1p1 /mnt/boot
cp -rv /mnt/boot/* /mnt/backup/boot/

重新分区:

1
fdisk /dev/nvme0n1

这次的分区如下表:

分区文件系统大小
/dev/nvme0n1p1fat32128M
/dev/nvme0n1p2swap64G
/dev/nvme0n1p3ZFSALL
1
mkswap /dev/nvme0n1p2

重建ZFS

创建ZFS池:

1
zpool create -f -o ashift=12 -o cachefile=/etc/zfs/zpool.cache -O compression=lz4 -O xattr=sa -O relatime=on -O acltype=posixacl -O dedup=off   -m none -R /mnt/gentoo rock /dev/disk/by-id/nvme-eui.000000000000001000080d0200600f01-part3

创建rock/os数据集:

1
zfs create -o mountpoint=none -o canmount=off   -o encryption=on -o keyformat=passphrase rock/os

恢复快照

卸除挂载:

1
zfs umount backup/2021-02-27-0000-01-backup

现在就可以恢复快照了:

1
zfs send backup/2021-02-27-0000-01-backup | zfs recv -F  -x encryption   rock/os/gentoo

更改fstab和Bootload信息

进入chroot

首先更改挂载分区设置:

1
zfs set mountpoint=/mnt/gentoo rock/os/gentoo

拷贝ZFS池缓存文件

1
2
mkdir -pv /mnt/gentoo/etc/zfs
cp -v  /etc/zfs/zpool.cache /mnt/gentoo/etc/zfs

拷贝网络的DNS

1
cp --dereference /etc/resolv.conf /mnt/gentoo/etc/

挂载必要的文件系统

1
2
3
4
5
mount --types proc /proc /mnt/gentoo/proc
mount --rbind /sys /mnt/gentoo/sys
mount --make-rslave /mnt/gentoo/sys
mount --rbind /dev /mnt/gentoo/dev
mount --make-rslave /mnt/gentoo/dev

我们不是在官方的Livecd下面还需要执行:

1
2
3
test -L /dev/shm && rm /dev/shm && mkdir /dev/shm
mount --types tmpfs --options nosuid,nodev,noexec shm /dev/shm
chmod 1777 /dev/shm

进入chroot

1
2
3
chroot /mnt/gentoo /bin/bash
source /etc/profile
export PS1="(chroot) $PS1"

修改fstab文件

修改fstab文件:

1
2
3
/dev/nvme0n1p1      	/boot     	vfat      	rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro	0 2
# /dev/nvme0n1p2
/dev/nvme0n1p2      	none      	swap      	defaults,pri=-2	0 0

bootload和内核

挂载分区

1
mount -v /dev/nvme0n1p1 /boot

安装bootload

1
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=Gentoo

修改grub配置文件

1
GRUB_CMDLINE_LINUX="dozfs root=ZFS=rock/os/gentoo"

安装内核和initramfs

1
2
3
cd /usr/src/linux
make install
genkernel initramfs --zfs --compress-initramfs

生成grub配置文件:

1
grub-mkconfig -o /boot/grub/grub.cfg

重启

退出当前的chroot环境:

1
exit

重启系统

1
reboot

重启之后第一次可能还是没办法正常进入系统,需要进入到shell里面导入一下zpool

1
zpool import -f rock

设置一下分区挂载点

1
zfs set mountpoint=/ rock/os/gentoo

然后再重启一下就可以正常进入系统了。

定期备份

在Gentoo的Portage Tree中提供了一个sys-fs/zfs-auto-snapshot的包,这个包可以帮我们创建一个定时任务周期性的备份我们的ZFS

1
sudo emerge -av sys-fs/zfs-auto-snapshot

可以根据需要配置备份的周期:

1
2
sudo zfs set com.sun:auto-snapshot:daily=true rock/os/gentoo
sudo zfs set com.sun:auto-snapshot:weekly=true rock/os/gentoo

后续工作

这次备份因为刚开始用ZFS很多地方不是很了解,然后用备份盘的时候吧系统导出去了(非加密的状态)。所以这里还是要再把这个备份盘格式化一下:

1
sudo dd if=/dev/urandom of=/dev/sdc bs=1M status=progress && sync

结束语

这次搞得备份有点崩了,幸好是在开始备份之前在学姐的NAS上备份了一份不然真的就没了:-P

这次备份过程中也发现了可能存在的很有意思的玩法,比如说给虚拟机快速装一个和宿主机一样的系统,或者是创建基于当前的gentoo创建一个testing分支的dataset等等,这些玩法也会在后面的文章中记录。

参考资料