建立强大的备份系统

发布于 28 天前  115 次阅读


引子

为啥子要备份捏?

  • 作为Arch用户,一旦系统出现问题,可以立即恢复
  • 作为Arch用户,配置高度定制化系统耗时长
  • 因为特殊原因,我在使用SMR硬盘,挂掉概率高
  • 即使电脑丢失/被黑/爆炸,也能保障数据
  • 可以在其它设备上迅速克隆出来一个一模一样的系统
  • 我想备份我的服务器
  • 预防地震、火灾等不可抗因素
  • ······

备份方案

以下是我使用到的一些备份软件、硬件等

  • dm-crypt 数据加密
  • rsync 备份数据
  • btrfs 文件系统
  • 1T 旧硬盘用于本地备份
  • 1T rsync服务器用于异地备份
  • 代理服务器 用于加速传输
  • ······

PS:我的/目录是Ext4文件系统,所以采用rsync+btrfs。如果你的/目录本身就是btrfs,这篇文章不一定适合你。

特性

我这套备份方案的优缺点如下:

优点

  • 良好的数据加密
  • 全系统备份
  • 增量备份
  • 增量同步到服务器
  • 同步时支持断点续传
  • 支持异地备份(可选)
  • 快速创建/删除备份
  • 文件压缩
  • 支持备份文件只读(借助子卷)
  • ······

缺点

以下缺点均是为异地备份做出的妥协:

  • 传输过程不能使用TLS
  • ssh传输性能低
  • 稀疏文件使写入性能下降
  • 扩容时可能导致备份损坏
  • 你需要花钱买一个大硬盘服务器或者对象存储

阅读方法

  • 红色内容代表警告,你应该仔细查看警告内容!否则可能损毁系统!!!
  • 橙色内容代表注意,你应该留心橙色内容,以正确使用!!
  • 蓝色代表提醒,以突出显示较重要内容!
  • 黑色为一般文字。

警告:你不能直接无脑copy任意一条命令,运行命令前请先动脑子!想清楚了再执行!

参考及要求

参考链接

备份这个东西,每个人的需求可能不一样,有的人只需要使用网盘备份文件,而有的人需要复杂的备份系统。我把一些参考链接放在这里,如果你不喜欢我的方法,你也可以定制自己的备份方法。除此之外你需要英语阅读能力。

上面的链接是几个比较有用的,你还需要自己搜索内容。rsync/btrfs分区/dm-crypt都是强大的工具,可能需要一段时间理解。

要求

  • Arch用户
  • 英语阅读能力
  • 了解btrfs的子卷、snapshot含义
  • dm-crypt基本使用方法
  • rsync基本使用方法
  • 熟悉Linux基本命令

我以后可能会写相关博文

格式化硬盘

由于我需要异地备份,网上目前没有相关教程,而btrfs压根不支持异地备份,令人头大。所以我的硬盘采用:

Ext4作为底层文件系统,在其上建立一个虚拟加密卷,并格式化成btrfs。(禁止套娃)

虚拟加密盘需要把内容储存到一个文件里,我们可以创建一个文件,文件的大小决定了虚拟加密盘的大小。这样我只需要备份虚拟加密卷就完事了。下面,你需要先把移动硬盘连接到电脑上。

警告:如果你不需要异地备份,你应该用luks模式直接加密整个移动硬盘,而不是采用下方的虚拟卷方式!

注意:创建的稀疏文件大小还应该考虑你的同步工具是什么,你应该了解你的同步工具在实现增量更新的时候是否会rewrite原文件,如果需要rewrite,那么服务器可利用空间为最大剩余容量的50%,rsync具有-inplace选项以取消rewrite(你也可以将文件拆分,提升利用率)。

注意:(不使用rsync做异地备份请忽略)即使rsync的-P选项可以处理稀疏文件,但是它依旧极其占用CPU、内存、网络,且工作不正常。对于本文的来说,稀疏文件应该尽可能接近当前系统体积。如果你是高阶用户,或者备份整个服务器系统,你应该根据实际情况调整大小.。

lsblk #查看你的硬盘以及分区状况
#如果你还没有分区或者有不用的分区,你需要使用cgdisk/cfdisk等建立分区
#以下以sdb1作为移动硬盘分区
sudo mkfs.ext4 /dev/sdb1 #将sdb1格式化成ext4文件系统
mkdir /mnt/d1
mkdir /mnt/d2
sudo mount /dev/sdb1 /mnt/d1 #挂载/dev/sdb1到/mnt/d1
sudo chmod 777 /mnt/d1 #改变目录权限,让非root用户能够读写移动硬盘 
truncate -s 30G /mnt/d1/backup.iso #瞬间创建一个30G的空洞文件,可以以其它后缀名结尾,比如vol、img等
cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 10000 luksFormat /mnt/d1/backup.iso #根据引导完成创建
sudo cryptsetup luksOpen /mnt/d1/backup.iso backup #打开虚拟加密卷
sudo mkfs.btrfs /dev/mapper/backup #把虚拟加密卷格式化为btrfs文件系统
sudo mount /dev/mapper/backup /mnt/d2 #把虚拟加密卷挂载到/mnt/d2
sudo chmod 777 /mnt/d2
df -hT #查看当前挂载情况

通过以上命令:

  • 把你的移动硬盘格式化成了Ext4文件系统
  • 将硬盘挂载到了/mnt/d1
  • 使用dm-crypt在硬盘上创建了一个虚拟加密卷
  • 将虚拟加密卷并格式化成Btrfs
  • 将虚拟加密卷挂载到了/mnt/d2

你还可以使用验证文件来代替密码

稀疏文件实际大小

关于稀疏文件在Linux系统的储存方式,这里我就不多说了,如果你想深入了解,你可以看看

我们先前使用了truncate创建的是30G的稀疏文件backup.iso。但是,实际上它占用的空间并不是30G,你可以使用下列命令查看相关信息。

du -h --apparent-size /mnt/d1/backup.iso #查看最大大小
du -h file.img #查看实际占用

弹出硬盘

这里插播一下弹出硬盘的方法

sudo umount /mnt/d2
sudo cryptsetup luksClose backup
sudo umount /mnt/d1

如果出现无法卸载的情况,关闭文件管理等应用,重新打开终端,输入sync命令,把缓冲区文件写入磁盘。

输入上述命令后,点击系统托盘里那个移除设备的小三角(部分系统要点两次,第一次是挂载,第二次是弹出)或者输入下面这个命令。

sudo udisksctl power-off --block-device /dev/sdb

这么做是为了使机械硬盘停转,磁头复位,主动防止磁头刮伤盘面。对应SSD/U盘的话就是使主控断电,延长使用寿命。

如果你使用3.5寸硬盘/外置供电,你可以在输完命令后直接断开USB数据线,硬盘停转后,关闭电源。

备份策略

啥?你刚刚试了把硬盘弹出?没关系,再试一遍挂载过程。

如果你要理解下面的内容,需要先搞清楚btrfs文件系统的工作方法。

现在有两种备份策略,我们先cd到当前btrfs文件系统所在的路径,对于本文是/mnt/d2

单一卷

PS:这名字是我取的,其实也不能这么叫,但是也没确切的说法

将所有文件使用rsync备份到根卷的同一目录下,然后直接创建snapshot子卷,目录树像这样

/mnt/d2(rootvol,dir, rw)
├── bin(dir)
├── boot(dir)
├── home(dir)
├── ···
├── backup2020.1.1(subvol, snapshot, ro)
│    ├── bin
│    ├── boot
│    ├── home
│    └── ···
└── backupt2020.2.1(subvol, snapshot, ro)
      ├── bin
      ├── boot
      ├── home
      └── ···

多目录

/mnt/d2(rootvol,dir, rw)
├── bin(dir)
│    ├current(rootvol, rw)
│    ├bin2020.1.1(subvol, snapshot, ro)
│    └bin2020.2.1(subvol, snapshot, ro)
├── boot(dir)
│    ├current(rootvol, rw)
│    ├boot2020.1.1(subvol, snapshot, ro)
│    └boot2020.2.1(subvol, snapshot, ro)
├── home(dir)
│    ├current(rootvol, rw)
│    ├home2020.1.1(subvol, snapshot, ro)
│    └home2020.2.1(subvol, snapshot, ro)
├── others(dir)
│    ├current(rootvol, rw)
│    ├others2020.1.1(subvol, snapshot, ro)
│    └others2020.2.1(subvol, snapshot, ro)
├── ···

选择方法

单一卷更加简单,备份、恢复更加方便。第二个目录分类更精细,可以轻松实现不同目录下不同频率/日期备份吗,区别管理。当然单一卷也可以实现不同日期备份,但是不直观。

PS:不管你使用哪种方法,均不会影响备份速度和稳定性!换句话说,两者性能相似。对于本文,我们选择第一种备份方案。

除此之外,你还可以使用多个加密卷,对不同目录区别加密来提高安全性。

开始备份

以下,我们使用rsync命令,将当前系统内容同步到btrfs分区(位于/mnt/d2)

sudo rsync -avAXP --stats --delete --dry-run --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/home/vince/[a-z]*","/home/vince/[A-Z]*"} / /mnt/d2/arch_bak

rsync的一大串命令,下面我们来解析一下:

  • -a archive模式
  • -A 添加ACL,选择性备份文件
  • -v和-P 显示详细进度
  • -stats 显示单个文件进度
  • -X 保留扩展属性
  • --delete 实现增量备份,再次备份时会在备份中删除已删除文件
  • --dry-run 模拟运行
  • --exclude 支持ACL名单,排除不需要的部分

上面的ACL名单里,排除了压根不用备份的目录以及挂载目录,防止备份进入死循环。我没有备份home目录下以英文字母开头的文件夹,但是备份了隐藏文件。你应该根据自己的需求,来写排除的部分。

最后的/表示系统根目录,也就是说全系统备份。/mnt/d2/arch_bak表示备份位置,也就是说我在btrfs根卷下建立了一个文件夹,名字叫arch_bak,免得一打开btrfs卷全是文件夹。这样,我还可以备份其它系统,方便管理。

在你模拟运行后,确定没问题了,删除--dry-run直接备份即可。

注意:在以后的备份过程中,你都应该加上--dry-run来模拟,看看rsync要删除哪些文件,一旦输错地址可以及时发现,避免损坏备份甚至摧毁系统(有点像dd)。

制作snapshot

snapshot理解成快照就好啦!就像拍照片一样,给你当前的btrfs分区拍个照,记录每个文件的样子。由于btrfs是Copy-on-write系统(前提是你没把默认打开的Copy-on-write功能关掉),所以我们可以瞬间创建出来一个快照。

btrfs的snapshot以子卷(subvolume)形式储存,snapshot默认不会备份子卷,所以当你有了一个快照的时候,不用担心下一个snapshot会包含前一个snapshot。

来自Archwiki的一句话:快照不是递归包含的,这意味着子卷内的子卷在快照里是空目录。

mkdir /mnt/d2/snapshots
mkdir /mnt/d2/snapshots/arch_snapshots
sudo btrfs subvolume snapshot -r /mnt/d2 /mnt/d2/snapshots/arch_snapshots/$(date +'%Y-%m-%d_%H-%M')

-r 表示创建一个只读快照。如果你想更改这个快照内容,你需要为只读快照再创建一个快照,就可以获得一个只读快照的可写入副本.

现在我们在/mnt/d2/snapshots/arch_snapshot目录下创建了一个以时间命名的快照。

PS:btrfs的快照是卷的概念,所以你不能为某一目录创建快照,而是直接为某个根卷或子卷创建。我们打开刚刚创建的快照,就会发现我们的快照里包含snapshots/arch_snapshot目录。如果你不想要这些空目录,那就把快照创建到一个子卷里(子卷嵌套)。对于本片文章,除非你是重度强迫症,否则完全没必要。

删除snapshot

我的习惯是保留3次快照。所以我需要删除过旧的快照。前面说过,snapshot以subvolume的形式存在,所以删除子卷即可。

sudo btrfs subvolume delete /mnt/d2/snapshots/arch_snapshot/subvol_name
#subvol_name是子卷名,对于本文,子卷名是日期_时间
sudo btrfs filesystem defragment /mnt/d2 #整理碎片

扩容btrfs卷

如果你没有使用虚拟加密卷,请忽略这一章节。

之前,我们创建了一个大小为30G的虚拟加密卷,并且格式化成了btrfs。如果我们的加密卷不够用了,现在我们要扩容加密卷。原理就是在原先文件的末尾增加数据,接着增大加密卷大小,最后扩展btrfs分区。

警告

  • 以下操作过程可能会损坏你的备份,请提前做好措施!
  • 请按照目录弹出硬盘部分关闭加密卷,只保留移动硬盘的挂载
  • 请仔细阅读以下内容!!!

过程中,如果出现了btrfs分区损坏,你可以看看Btrfsck页面Manpage/btrfs-check页面

truncate -s 512G /mnt/d1/backup.iso
#把backup.iso扩容到512G,是扩容到,不是增加!
sudo cryptsetup luksOpen /mnt/d1/backup.iso backup
sudo cryptsetup resize /dev/mapper/backup
sudo btrfs check -p /dev/mapper/backup #校验分区是否受损
sudo btrfs filesystem resize max /dev/mapper/backup
sudo mount /dev/mapper/backup /mnt/d2 

此时我们就能看到分区大小的变化啦!

上传备份到服务器

关于异地备份的一些想法:

本篇文章使用了传输前的加密,来保障数据安全,传输过程中使用ssh。如果你不想这么做,还想要异地备份,你可以试试使用VPN网络来实现流量加密,确保信息安全,在服务器端你可以直接加密一个分区,或创建一个虚拟加密卷用于存储。

采用什么方法上传就是仁者见仁,智者见智了,根据你的环境自主选择。对于在这里我依旧选择可操作程度较高的rsync。你也可以使用带有校验、差异同步功能的网盘(貌似免费的百度云挺香,反正备份下载次数少)、BT协议(借助bt工具,如resilio sync、syncing还可以轻松实现一中心多地多备份)等。甚至架设本地服务器(FTP/HTTP下载),让备份服务器主动下载。

注意:差异同步、增量同步是两个重要属性!应该优先选择支持这两个属性的工具,其次还应注意服务器允许存储的最大文件大小。

如果你想要使用网盘,你可以看看这个页面:Comparison of online backup services,所以百度云香极了!全部支持还免费,网络环境好,不限制上传?!缺点就是下载的时候。。。

本文采用rsync的方式,所以首先你得有一个rsync服务器,建议运行在DAEMON模式。其次如果你的网络不好,你可能需要一个代理服务器。为了服务器安全性,你至少需要更改ssh端口,并采用证书验证。下面是两个教程

在确保了服务器的安全性了之后我们开始对文件进行上传。先在假设有一个socks5代理监听在本地1080端口,我们需要用netcat(OpenBSD版本)实现ssh over socks5进行加速。如果你没有netcat,用包管理器安装一个!

PS:对于天朝用户,如果你的rsync服务器如果在国外,请考虑ssh加代理或者直接使用rsync的明文传输。我更倾向于前者。如果服务器性能足够而带宽不足,可以考虑添加-z选项来加快传输,上传下载均适用。

初次上传

rsync -avSP -o "ssh -i /path/to/private/key -p 22 -o 'ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p'" /mnt/d1/backup.iso [email protected]:/home/rsync

当前使用了证书验证,并假设有个代理监听在1080端口,请根据实际情况修改部分内容

-S代表文件为稀疏文件,让rsync进行优化。然而我在实际使用过程中,它老老实实地上传了30个G???目前暂不清除原因,没有看到相关问题。你还可以在rsync后面加上-c参数,实现checksum。当然它计算的是md5,而且对于大文件比较耗时,我的小服务器是吃不消的

/(ㄒoㄒ)/~~。顿时感觉网盘更香了!!!

更新上传

rsync -avSP --append  --inplace --partial -o "ssh -i /path/to/private/key -p 22 -o 'ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p'" /mnt/d1/backup.iso [email protected]:/home/rsync

上面的--inplace 取消rewrite属性,--append 增量同步。关于为什么要这么做可以看看Copying large files with Rsync, and some misconceptions

断点续传

关于断点续传,我们之前的两个命令都含有-P参数,所以如果在上传的同时网络断开了,只需要重复输入一个一模一样的命令

恢复

说明

rsync属于文件级别备份,而非块级/原子级,它更灵活也更复杂,所以分成以下两种恢复过程。你应该有一个LiveCD的Linux U盘,任何发行版均可。然后开始按照下面的操作恢复系统。

首先找到你的备份硬盘,老样子,挂载它。如果你按照上面的方法进行了异地备份,则可以使用下面这个命令来下载备份。

rsync -avz -o "ssh -i /path/to/private/key -p 22 -o 'ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p'" [email protected]:/home/rsync/backup.iso /mnt/d1

磁盘情况

以下内容,我们以

  • /dev/sda为Live USB
  • /dev/sdb为预恢复的磁盘
  • /dev/sdc为我们的移动硬盘(储存着加密的备份文件)
  • 虚拟加密卷挂载到/run/d1

UEFI系统(GTP)

  • /dev/sdb1为UEFI分区,大小512MB
  • /dev/sdb2为swap分区
  • /dev/sdb3为Ext4(/目录)

如果你有其它分区,请自行分区、挂载!

传统启动(MBR)

本片文章只记录UEFI情况,对于传统启动,只是没了上述的/dev/sdb1(EFI分区)其它情况均相同

注意:如果你的系统是损坏了文件,你可以直接按照下面的操作恢复。如果磁盘的分区表损坏,磁盘压根不能用了或需要克隆一个系统,你应该先看下面的磁盘损毁/克隆系统。

系统文件损毁

挂载文件系统

sudo mount /dev/sdb3 /mnt
sudo mkdir /mnt/boot
sudo mount /dev/sdb1 /mnt/boot
sudo swapon /dev/sdb2

安装cryptsetup然后按照之前的方法打开加密卷,挂载到/run/d1,然后运行就完成了系统的恢复!

sudo rsync -avAXP --stats --delete --dry-run --exclude={"lost+found","snapshots"} /run/d1/arch_bak /mnt 

如果你想用snapshots里的内容恢复,十分简单,修改一下rsync的读取目录和exclude内容就行。

磁盘损毁/克隆系统

使用工具分区

注意:对于UEFI,你应该使用cgdisk,否则你应该使用cfdisk分区。而且应该尽量保持分区同之前一致!

lsblk #查看磁盘
cgdisk /dev/sdb #使用cgdisk,重新分区

建立文件系统,并挂载

mkfs.vfat /dev/sdb1
mkswap /dev/sdb2
mkfs.ext4 /dev/sdb3

把/(就是要恢复的硬盘)挂载到/mnt,把UEFI分区挂载到/mnt/boot,使用swapon命令启用交换空间

sudo mount /dev/sdb3 /mnt
sudo mkdir /mnt/boot
sudo mount /dev/sdb1 /mnt/boot
sudo swapon /dev/sdb2

使用rsync恢复系统

一切准备基本就绪,按照上面的系统文件损毁部分使用rsync命令恢复系统文件。

重装GRUB

接着进入chroot。我们以arch系统为例,其它系统均类似。

PS:对于arch用户,使用arch-chroot,如果你的liveUSB不是arch(例如Ubuntu),你可以使用包管理器(例如apt)安装一个arch-install-scripts,然后就可以使用arch-chroot啦。其它发行版请查阅手动安装文档。

arch-chroot /mnt /bin/bash #使用chroot
pacman -S grub os-prober #安装grub和os-prober
#grub-install
#对于UEFI系统
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub --recheck
#对于MBR
grub-install --target=i386-pc /dev/sdb --recheck
#重新生成grub.cfg
grub-mkconfig -o /boot/grub/grub.cfg

好啦!你已经恢复了你的系统!

结束

原作者(Vince)的话:写文不易,为了知识共享我不限制转载、再创作等,请各位姥爷在转载和再创作时留个链接和原作者。同时希望你能严格遵守 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

我本学生,若能投食,请微信/支付宝扫描下面这个二维码!感激不尽!

建立强大的备份系统

长风破浪会有时,直挂云帆济沧海。在这条路上一直走下去!