Mr Sunshine

Linux 全系统复制

千盼万盼,终于盼来实验室的 7 台 R715 集群,捣腾了两天好不容易才把机器和交换机都安上机架。机器有点多,我们不想每台机器都重新配置一遍环境,所以准备先配好一台机器再复制到其他机器的硬盘上。

方案 1 – 全盘复制

直接复制整个硬盘,这样包括 boot loader 和分区表在内的硬盘所有信息都能完整的复制过去。不过目标盘的容量不能比复制源低,否则文件系统就悲剧了。这种方法需要拷贝整个硬盘,即使你什么文件也没写,所以速度非常慢。

可以用 dd 复制单块硬盘


1
dd if=/dev/sda of=/dev/sdb& ddpid=$!

dd 会很慢,可以向 dd 进程发 USR1 信号监控 dd 进展

1
kill -USR1 $ddpid

也可以同时复制到多块硬盘

1
dd if=/dev/sda | tee >(dd of=/dev/sdb) >(dd of=/dev/sdc) >(dd of=/dev/sdd) > /dev/null

另外还有 G4L 和 CloneZilla 这样的工具可以全盘复制,不过我们觉得还是太慢了,500G 的硬盘居然复制了 11 个小时……

方案 2 – 人肉搬家

1) 用 cfdisk/fdisk 建好要目标硬盘的分区表,mkfs.ext4/mkswap 创建好文件系统和 swap 分区后,把文件系统 mount 上来

2-1) 我们装的是 Debian squeeze 系统,/etc/fstab 中的设备是用 uuid 而不是 /dev/sdb1 这样的设备名的,所以得把其中的 uuid 改成新磁盘上相应分区的 uuid

可以先查看目标盘分区的 uuid:

1
ll /dev/disk/by-uuid

这个目录里的每个文件都是一个 uuid 到实际设备的映射(软链接的形式)

然后再根据这些映射更新 /etc/fstab 中相应设备的 uuid。当然我们也可以通过自定义 udev[2] 规则固定设备名称,然后直接在 /etc/fstab 中直接填设备名就好了。

2-2) 复制文件系统根目录,注意要排除目标盘 mount 的目录和系统自己 mount 的目录(可以用 mount -l 查看,比如 /proc,/sys 这些目录)

1
tar c --exclude=/proc/* --exclude=$EXCLUDE_DIR / | (cd /mnt/sdb2; tar x)

3) 安装 boot loader

一开始我们以为直接用 dd 复制源硬盘 MBR 的前 446 字节(启动代码部分)过去就可以了,但启动发现连 grub 菜单都进不去。

其实 grub 启动包含了两个阶段的代码,第一阶段代码是在 MBR 里的,第二阶段在文件系统上,那么 grub 如何从第一阶段跳转到第二阶段呢?它是把第二阶段代码所在的磁盘扇区位置记录在 MBR 中 [1]。而这份代码在每块硬盘上的位置肯定是不一样的,于是 grub 没办法跳转到第二阶段继续执行。

所以我们得重新安装 boot loader:

1
grub-install --root-directory=/mnt/sdb2

这里–root-directory 是告诉 grub 说我们的根文件系统是在 sdb2 上而不是源硬盘上,一开始我们没指定就悲剧了。

现在把目标盘装回其他机器,不出意外应该就成功了。

[1] The GRUB MBR

[2] udev