![手动克隆/重新创建虚拟磁盘](https://linux22.com/image/1377033/%E6%89%8B%E5%8A%A8%E5%85%8B%E9%9A%86%2F%E9%87%8D%E6%96%B0%E5%88%9B%E5%BB%BA%E8%99%9A%E6%8B%9F%E7%A3%81%E7%9B%98.png)
我正在尝试以相当手动的方式克隆虚拟磁盘映像。到目前为止,我的方法概述如下:
- 使用 120GB HDD 在 VirtualBox 中创建虚拟机(虚拟机管理程序和 HDD 大小无关紧要,主要是为了完整性和与我的其余问题的一致性,例如分区大小)
- 在虚拟机上安装 Ubuntu 12.04.3
- 关闭虚拟机
- 挂载与虚拟机关联的虚拟硬盘
- 提取操作系统文件和数据并存储在目录中
- 保存虚拟硬盘元数据
- 创建新的虚拟磁盘并从中恢复分区和启动信息(6)
- 将(5)中的数据恢复到正确的分区
问题
我的复制虚拟机无法启动。Grub 似乎复制了,并且出现确认我的根分区(上面安装了 Ubuntu)。我可以启动一次 Grub,然后出现紫色屏幕,好像 Ubuntu 即将加载。然后它停止了。之后,我可以启动到 Grub,选择我的操作系统,然后我得到一个闪烁的命令行光标。无法输入。我怀疑克隆过程中我遗漏了一些东西(有关更多详细信息,请参阅下文)。注意:我使用的是 grub2,而不是旧版。
你为什么做这个?
作为合同要求的一部分,我需要将虚拟磁盘存储在版本控制中。在版本控制中拥有一个巨大的二进制 blob(虚拟磁盘)是一件麻烦事,主要是用于 clone(git)/checkout(svn),但也用于 diff。我考虑过压缩到多个文件,但我需要能够操作上面 (5) 中提取的操作系统/数据。请注意,我的 VCS 存储库仍然需要构建完整 VM 所需的所有信息。
细节
重现我所描述的内容的详细说明:
- 创建虚拟机并启动 Ubuntu Live CD
- 选择“试用 Ubuntu”
- 打开终端
- 创建 msdos 分区:sudo parted /dev/sda mklabel msdos
- 创建一个 2GB 的交换文件: sudo parted /dev/sda mkpart primary linux-swap 2048s 4198399s
- 将驱动器的其余部分用于根分区:sudo parted /dev/sda mkpart primary ext4 4198400s 100%
- 重启机器,选择“安装 Ubuntu”
- 选择高级分区选项
- 双击交换分区,选择将其用作交换
- 双击根分区,选择格式化并将其用作根(/)挂载点
现在,执行以下操作来克隆磁盘:
# Set up some parameters
ORIG_DEV="/dev/nbd0"
ORIG_MNT=$(mktemp -d)
ORIG_IMG="orig.vdi"
CLONE_DEV="/dev/nbd1"
CLONE_MNT=$(mktemp -d)
CLONE_IMG="clone.vdi"
qemu-img info $ORIG_IMG # save the "virtual size" output (in bytes) in the
# VIRT_SIZE variable in the next command
VIRT_SIZE="128849018880"
# Create the clone disk
qemu-img create -f vdi $CLONE_IMG $VIRT_SIZE
# Use qemu to make both disks accessible
modprobe nbd
qemu-nbd -c $ORIG_DEV $ORIG_IMG
qemu-nbd -c $CLONE_DEV $CLONE_IMG
# Set up the clone disk partition table and partitions
parted $CLONE_DEV mklabel msdos
parted $CLONE_DEV mkpart primary linux-swap 2048s 4198399s
parted $CLONE_DEV mkpart primary ext4 4198400s 100%
# Format the clone disk partitions and clone the UUIDs
mkswap $CLONE_DEVp1 -U $(blkid $ORIG_DEVp1 -s UUID -o value)
mkfs.ext4 $CLONE_DEVp2 -U $(blkid $ORIG_DEVp2 -s UUID -o value)
# Mount both disks and copy root from the original to the clone
mount $CLONE_DEVp2 $CLONE_MNT
mount $ORIG_DEVp2 $ORIG_MNT
find $ORIG_MNT -maxdepth 1 -mindepth 1 | xargs -I{} cp -ar {} $CLONE_MNT
umount $ORIG_MNT
umount $CLONE_MNT
# Copy the boot sector and partition table from the original
dd if=$ORIG_DEV of=$CLONE_DEV bs=$((2048*512)) count=1
# Disconnect the disks
qemu-nbd -d $CLONE_DEV
qemu-nbd -d $ORIG_DEV
您还尝试过什么?
- grub-install --root-directory=/path/to/clone/device/boot/ /dev/clone_device。这会将 Grub 安装在正确的设备上,但使用我的主机的设备详细信息。虚拟机无法启动。
- chroot 进入克隆磁盘,然后 grub-install。遇到了麻烦,因为我必须能够使用 64 位主机来克隆 32 位客户机。这似乎是一条值得研究的有希望的途径,但我不知道如何实现这一点。
- 安装虚拟磁盘,使用 将所有文件移出数据分区
mv
,将数据和交换分区清零(dd if=/dev/zero of=/dev/nbd0p2
)并压缩虚拟磁盘(使用VBoxManage modifyhd clone.vdi --compress
)。磁盘开始在我的主机文件系统上扩展,因为它正在用空白空间填充它(哈哈!)。dd
当我意识到这种情况发生时,我停止了,然后压缩了磁盘映像。它仍然超过 3GB。(我还没有尝试使用 gzip/bzip,我将在今晚开始尝试。我还将尝试让 dd wipe 运行完成,但我更喜欢一个耗时较少的解决方案,即使它有效)。 - e2image。请参阅我的另一个问题:e2image 恢复文件系统元数据。我还没有解决这个问题。请注意,我在细节部分,包括分区创建、格式化和引导扇区复制,但前我复制根分区,生成一个与 e2image 创建的图像文件大小非常相似的图像文件。
- 启动另一台虚拟机,将其 chroot 到此虚拟机中以运行 grub-install。我实际上没有这样做过,但我将其包含在这里以防有人建议这样做。对于我的用户,我需要虚拟机的重组可编写脚本;这可以避免复杂的设置过程。
- 安装 extlinux 而不是 Grub。虽然不成功,但这个练习表明(我认为!)引导加载程序已成功从我的分区加载 RAM 磁盘,但此时卡住了。
如果您已经读到这里,谢谢您!任何有关调查途径的建议,无论多么不详细,都将不胜感激。提前致谢。
答案1
我有一个替代建议,它省去了提取和重新创建虚拟磁盘内容的需要。
如果您使用 git,您可以直接在已安装的虚拟磁盘上工作,并将 .git 目录放在其他位置。唯一的问题是您可能需要将 .gitignore(如果有)放在虚拟磁盘根分区的根目录中。
编辑:
对于克隆,您可以在初始安装后使用 VirtualBox 的正常机制。每当您需要恢复特定版本时,请从原始版本创建另一个克隆,然后挂载它并执行 git checkout。
只要 grub 版本没有差异,这就是您需要做的一切。如果 grub 版本不同,您将需要从 12.04.3.iso 启动 VM 并执行 grub-install。
这样,替代的工作流程是(新增步骤4,修改步骤5):
- 使用 120GB HDD 在 VirtualBox 中创建虚拟机
- 在虚拟机上安装 Ubuntu 12.04.3
- 关闭虚拟机
- 克隆虚拟机,将原始虚拟机放在一边
- 挂载原始或第一个克隆的虚拟硬盘(例如在 /media/virtual 中)
- cd /媒体/虚拟
- git --git-dir=/somewhere/else/virtual.git --work-tree=. init
- git --git-dir=/somewhere/else/virtual.git --work-tree=.添加 .
- git --git-dir=/somewhere/else/virtual.git --work-tree=.commit -m “初始导入”
- ... 任何其他 git 任务...
如果你不想总是添加--git-dir=/somewhere/else/virtual.git --work-tree=.Stackoverflow 上有一个问题解释了如何摆脱它: 我可以将 .git 文件夹存储在我想要跟踪的文件之外吗?
虽然这并不是您所要求的,但是您的问题描述给我的印象是您对完成工作比对完成工作的具体方式更感兴趣。
答案2
也许您已经尝试过,也许还没有。但是,您是否尝试过在“复制的 VM”中从 Live CD 重新安装 Grub2?我读到的所有内容都听起来像是从主机安装 Grub2。
- 一旦出现无法启动的重复虚拟机
- 将 Live CD(例如 Ubuntu 安装盘)安装到虚拟机
- 启动虚拟机并按 F12 从 Live CD 启动
- 从命令行重新安装 grub(在虚拟机内部)
如果您想自动化该过程,您可以使用VBoxManage
安装自定义的 Ubuntu Live CD,该 CD 运行脚本以在启动时重新安装 Grub2。
VBoxManage storageattach "io" --storagectl "IDE Controller" \
--port 1 --device 0 --type dvddrive --medium debian-6.0.2.1-i386-CD-1.iso
希望不要太过时,有一个help.ubuntu.com 上有关自定义 Live CD 的指南以及 Stack Exchangeaskubuntu.com 上有关向自定义 Live CD 添加启动脚本的问题/答案
答案3
听起来你对 Ubuntu 挂载点不太了解?你考虑过将虚拟机分成多个分区吗?
来自以下链接:
http://www.easy-ubuntu-linux.com/ubuntu-installation-606-12.html
基本安装只有 4G,+1G 用于 SWAP,+2G 用于 /tmp,然后您可以为 /usr、/var、/home、/opt 创建单独的分区
一开始只需为每个文件分配 1G,必要时可以使用虚拟盒动态增加文件大小
参考:
http://www.ubuntugeek.com/linux-or-ubuntu-directory-structure.html
之后,您可以确定您的 SVC 范围,只有用户文件或日志或操作系统?这样您就可以减少版本的痛苦。
在大多数情况下,您只需在设置后将 /、/usr 和 /opt 设置为只读且不可更改,从而减少整体版本问题。
但有一点需要提醒,由于您的合同规定您需要存储虚拟磁盘,我猜存储从虚拟磁盘提取的数据与您的合同不符。但存储多个虚拟磁盘是匹配的。这就是为什么我建议您创建挂载点,然后将其中一部分设为只读(因此只有一个版本)。
还有一点需要注意,记得检查是否可以关闭挂载点的文件访问日期吗?(一些非常高安全性的设置不允许关闭该功能,计算机取证)
因为如果访问日期已打开,访问日期实际上会写入磁盘。因此,即使没有写入任何内容,第 2 天访问的虚拟磁盘/挂载点实际上与第 1 天的虚拟磁盘/挂载点是不同的版本。
参考(暂无访问时间):
https://askubuntu.com/questions/59179/how-do-i-make-noatime-mounts-default
答案4
再考虑一下,我会真正研究一下/etc/fstab
。您的分区在那里是如何定义的?如果它们是由它们的定义的UUID
,那么这些信息可能不会在克隆过程中被复制。您可能希望让它们由设备名称定义,例如/dev/sda0
。
还有一点,为什么不运行 git从内部虚拟机本身?我可以想象在主机上有一个包含您的存储库的目录。然后虚拟机可以挂载此目录并git
在虚拟机本身上运行。