Migrate a Virtual Machine from Full Disk to Single File-System Image

Full-disk images - that is to say a file containing an MBR, partition table and one or more partitions - are a pain in the arse to scale. Conventional wisdom tells us we should be able to do this with losetup and parted, or less gracefully with (c)fdisk but I've never had anything but trouble. In the end, it tends to be much easier to move the contents of the image to a file-system-only image and externalize the kernel since we'll no longer have the benefit of a bootloader.

Let's create and mount our new image to start off:

# dd if=/dev/zero of=newimage.img bs=1M count=4000
# mke2fs -j newimage.img
# mkdir /mnt/rawroot
# mount -o loop newimage.img /mnt/rawroot

Now we're going to mount our old full disk image's partition. Use kpartx -l to determine what node the partition will be mapped to:

# kpartx -l oldimage.hdd
loop34p1 : 0 4190208 /dev/loop34 2048

This tells us the full disk will be on /dev/loop34 and the partition itself will be on /dev/mapper/loop34p1.

# kpartx -a oldimage.hdd
# mkdir /mnt/rawroot2
# mount /dev/mapper/loop34p1 /mnt/rawroot2

Alternatively, we can let lomount do the work for us:

# lomount -diskimage oldimage.hdd -partition 1 /mnt/rawroot2

Now we'll copy the files in the old file system to the new image exactly as they stand:

# cd /mnt/
# cp -ax rawroot2/* rawroot/

It's important that we use the -a flag or we may end up breaking file system links and will almost certainly fill up the new image when we hit device nodes like /dev/zero, /dev/urandom and so on.

Edit the /etc/fstab in the new image and ensure it reflects the new configuration; / will probably come from /dev/xvda1. Old references by LABEL or UUID will no longer be valid.

Since we'll be forgoing a bootloader it is necessary to externalize the kernel and initrd images:

# cp rawroot2/boot/vmlinuz-3.2.0-29-generic /xen/myvm/
# cp rawroot2/boot/initrd.img-3.2.0-29-generic /xen/myvm/

Now we can unmount both images:

# umount rawroot
# umount rawroot2

If you used kpartx instead of lomount you should remove the old image from the loop device:

# kpartx -d oldimage.hdd

Now alter the Xen configuration file to reference the externalized kernel and initrd:

kernel = "/xen/myvm/vmlinuz-3.2.0-29-generic"
initrd = "/xen/myvm/initrd.img-3.2.0-29-generic"

Remove or comment your reference to pygrub and boot the machine. If everything went well you will be looking at a login prompt shortly.

Please see my article on resizing file system images for details on how to grow the new image.


There are no comments for this item.