sixg0000d
sixg0000d

使用 dd 命令向 VPS 中复制磁盘镜像

前言

由于在网上搜索 dd vpsdd 教程,搜索结果几乎全部是关于一键 dd 脚本的下载和使用教程,而难以找到自己使用 dd 命令复制磁盘镜像的相关指引,遂本人将实践作为记录,以供中文参考。如有错漏之处,敬请指正,多谢。

需求场景和依赖环境

  1. 向 VPS 中克隆式安装新系统,或恢复旧的备份
  2. VPS 为 KVM 虚拟化方式
  3. VPS 提供 Rescue mode,或提供从其他磁盘、内存、光驱启动的操作系统而不需要从目标磁盘(需要写入的磁盘)启动,该系统内 dd 命令可用

生成镜像

首先生成需要克隆的磁盘镜像。我在本地的 KVM 虚拟机中安装好 Fedora 33 的最小化安装系统(并作了一些修改,如修改 SSH 端口),准备将该系统复制到 Virmach 的 VPS 中以达到自定义安装 Fedora 的目的。

登陆本地的虚拟机

$ ssh -p 10086 'root@192.168.122.241'

列出块设备,找到需要克隆的块设备名称

$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom  
zram0  251:0    0  485M  0 disk [SWAP]
vda    252:0    0    5G  0 disk 
├─vda1 252:1    0    1G  0 part /boot
└─vda2 252:2    0    4G  0 part /

需要克隆的块设备名称是 vda,在文件系统中的路径为 /dev/vda

$ ls /dev/vda
/dev/vda

登出虚拟机

$ logout
Connection to 192.168.122.241 closed.

将块设备的数据写入到本地的镜像文件

$ ssh -p 10086 'root@192.168.122.241' 'dd bs=4096 if=/dev/vda' | gzip | dd of=f33-min.img.gz status=progress

或者

$ ssh -p 10086 'root@192.168.122.241' 'dd bs=4096 if=/dev/vda' | gzip | pv > f33-min.img.gz
ssh 命令的最后一个参数 dd bs=4096 if=/dev/vda 是在虚拟机内进行的,但会输出到本地
dd 命令的参数 bs=4096 表示设置每次读写 4096 字节,参数 if=/dev/vda 表示从 /dev/vda 读取数据,未设置参数 of= 故输出到 STDOUT
无参数的 gzip 命令对 STDIN 输入数据进行压缩并输出到 STDOUT 。由于除文件所在的磁盘扇区外大多为空数据,我们对数据进行压缩能得到一个较小的镜像文件,否则将得到一个和磁盘容量相等的镜像文件
dd 命令未设置参数 if= 则从 STDIN 读取数据,参数 of=f33-min.img.gz 表示输出到当前目录下的 f33-min.img.gz 文件当中(无则创建),参数 status=progress 表示将周期性的传输统计信息打印到 STDERR
pv 是一个命令行管道工具,可以实时打印管道的传输速率,可以配合重定向代替 dd status=progress of=/path/to/output

最后我们将在本地的当前目录下得到一个镜像文件的压缩文件 f33-min.img.gz

复制镜像

Virmach 、 RackNerd 等 VPS 商家提供的 SolusVM 面板能够很轻松的进入 Rescue mode,
Rescue 页面将会提供 SSH 登陆端口、密码等信息

密码等信息给出后,需要等待数分钟。Rescue mode 系统载入并开机后,用给出信息 SSH 登陆系统

$ ssh 'root@your_vps_ip'

Virmach 提供的 Rescue mode 其实是一个 Debian 9 (可能是一个从母鸡中分配出的 Ramdisk),登陆后先把元数据和包都升级一遍

$ apt update
$ apt upgrade
如果你的系统比较精简,需要安装一些必要的软件包,比如 dd 命令在 Debian 9 的 coreutils 包中,还有用于解压缩的 gzip

检查需要写入的磁盘的块设备名称和文件目录,然后登出

$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom  
vda    254:0    0   15G  0 disk 
├─vda1 254:1    0    1G  0 part 
└─vda2 254:2    0   14G  0 part 
vdb    254:16   0  1.1G  0 disk 
└─vdb1 254:17   0  1.1G  0 part /
$ ls /dev/vda
/dev/vda
$ logout
Connection to your_vps_ip closed.

然后上传镜像文件并写入 VPS 的块设备

使用 SSH 连接进行上传和写入比较简单,在本地执行

$ dd if=f33-min.img.gz status=progress | ssh 'root@your_vps_ip' 'gzip -d | dd bs=4096 of=/dev/vda'
命令 gzip -d 表示对 STDIN 输入数据进行解压并输出到 STDOUT

或者也可以将镜像文件上传至 Rescue mode 系统能访问到的互联网位置,再从 Rescue mode 系统下载并写入到磁盘。比如我将镜像文件上传至我的一个 http 服务器,可以通过 http://my.server.domain/files/f33-min.img.gz 访问和下载

登陆 Rescue mode 系统

$ ssh 'root@your_vps_ip'

安装 curl

$ apt install curl
即使无视网络环境,对磁盘进行 5.0 GiB 的写操作也需要很长时间,建议使用 screentmuxpm2 等工具,将进程挂至后台,以免 SSH 连接断开和中断操作

创建新的 screen 会话,名称为 dd

$ screen -S dd

使用 curl 从远端下载镜像,并同时用 dd 写入磁盘

$ curl -C - http://my.server.domain/files/f33-min.img.gz | gzip -d | dd of=/dev/vda status=progress
使用 screen 创建的会话,SSH 连接断开后并不会中断。可以在 screen 会话中按 Ctrl + A + D 组合键主动跳出当前会话,用 screen -r <会话名或会话pid> 命令回到会话,比如我创建的会话 "dd" 可以用 screen -r dd 恢复

curl 的参数 -C/--continue-at <offset> 代表从 <offset> 处恢复连接,而 -C - 代表自动从断开处恢复连接,也就是我们常说的“断点续传”。我之前尝试用 curl 完成 dd ,经常出现 gzip: unexpected end of file 的错误,添加该参数之后不再出现错误

完成后登出 SSH 会话

$ logout
Connection to your_vps_ip closed.

扩展磁盘

由于 VPS 的磁盘空间可能大于镜像的磁盘(可大于不可小于),我们可能需要在写入镜像后扩展块设备和磁盘文件系统的空间

A. 如果系统分区是 ext 系列文件系统

登陆 Rescue mode 系统

$ ssh 'root@your_vps_ip'

扩展块设备

$ e2fsck -f /dev/vda
$ resize2fs /dev/vda
# 若提示找不到命令,可能需要先从 `apt` 安装相应的文件系统工具包

然后方可关闭 Rescue mode 从磁盘启动

B. 如果系统分区是 Btrfs 文件系统

如果是 Btrfs 文件系统,我们可以在进入系统后完成扩盘操作,不必依赖 Rescue mode

关闭 Rescue mode ,从磁盘启动系统

禁用 Rescue mode
和启用 Rescue mode 一样,切回自己的磁盘引导并启动、开机需要等待数分钟

登陆 VPS

此时的 VPS 已是克隆的操作系统,除 IP 地址外,SSH 信息和本地虚拟机的基本一致
$ ssh -p 10086 'root@your_vps_ip'

cfdisk 等工具更改磁盘分区大小至最大,写入,并退出

$ cfdisk /dev/vda
用 cfdisk 扩展块设备
将修改后的分区表写入到磁盘

此时用 lsblk 命令查看块设备已扩展到最大可用空间,但用 df -h 命令查看文件系统大小尚未改变

$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom  
zram0  251:0    0  485M  0 disk [SWAP]
vda    252:0    0   15G  0 disk 
├─vda1 252:1    0    1G  0 part /boot
└─vda2 252:2    0   14G  0 part /
$ df -h
文件系统        容量  已用  可用 已用% 挂载点
devtmpfs        472M     0  472M    0% /dev
tmpfs           486M     0  486M    0% /dev/shm
tmpfs           195M  508K  194M    1% /run
/dev/vda2       4.0G  1.7G  1.9G   47% /
/dev/vda1      1014M  152M  863M   15% /boot
tmpfs           486M  4.0K  486M    1% /tmp
tmpfs            98M     0   98M    0% /run/user/0

此时只需使用如下命令:

$ btrfs filesystem resize max /

挂载到 / 的 Btrfs 文件系统就将扩展到最大可用空间:

$ df -h
文件系统        容量  已用  可用 已用% 挂载点
devtmpfs        472M     0  472M    0% /dev
tmpfs           486M     0  486M    0% /dev/shm
tmpfs           195M  512K  194M    1% /run
/dev/vda2        14G  1.7G   12G   13% /
/dev/vda1      1014M  152M  863M   15% /boot
tmpfs           486M  4.0K  486M    1% /tmp
tmpfs            98M     0   98M    0% /run/user/0

参考资料



CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论