使用 dd 命令向 VPS 中复制磁盘镜像
前言
由于在网上搜索 dd vps 或 dd 教程,搜索结果几乎全部是关于一键 dd 脚本的下载和使用教程,而难以找到自己使用 dd 命令复制磁盘镜像的相关指引,遂本人将实践作为记录,以供中文参考。如有错漏之处,敬请指正,多谢。
需求场景和依赖环境
- 向 VPS 中克隆式安装新系统,或恢复旧的备份
- VPS 为 KVM 虚拟化方式
- 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
复制镜像
密码等信息给出后,需要等待数分钟。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 的写操作也需要很长时间,建议使用 screen 或 tmux 、 pm2 等工具,将进程挂至后台,以免 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 ,从磁盘启动系统
登陆 VPS
此时的 VPS 已是克隆的操作系统,除 IP 地址外,SSH 信息和本地虚拟机的基本一致
$ ssh -p 10086 'root@your_vps_ip'
用 cfdisk 等工具更改磁盘分区大小至最大,写入,并退出
$ cfdisk /dev/vda
此时用 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
参考资料
- Copy a Disk Over SSH | Linode
- dd (Unix) - 维基百科,自由的百科全书
- Shell 的命令 - dd - 《阮一峰 Bash 脚本教程》 - 书栈网 · BookStack
喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。
发布评论…