There have been quite a few requests on forums and blog posts on a few sites we frequent asking someone to figure out how to move a virtual machine from EC2 to VirtualBox or KVM. We’ve got quite a bit of experience working with KVM so we figured why not try our hand at importing a virtual machine template from the Amazon AMI repository so that developers or sysadmins could run them in their local environments. We’ve already written a howto on importing an AMI from Amazon, so you may want to read that first, but this howto also applies to just creating a KVM or VirtualBox image from a linux filesystem of any kind. Right now this particular method only works with Linux but there are more OS agnostic (and much slower) methods for transposing virtual machines. So without further delay, let’s get started.
You’ll need at least 15 gigs of free space to make this work.
1) Download and unpack an AMI from Amazon
You can learn how to do that here, or if you have sufficient knowledge you can build a full linux filesystem
2) Prepare a new raw drive file
We’ll create a file backed drive, set it up so we can partition it and create a new filesystem.
Create the file by using the ‘dd’ command.
dd if=/dev/zero of=newimage.raw bs=1M count=10240
Add it to a loopback device
losetup -fv newimage.rawPartition the file backed loopback device. For this we’ll just create one partition which is the whole disk. Make sure its bootable.
cfdisk /dev/loop0
Write the partition and exit
Now we’re going to create a filesystem on the partition we just created. Please note that there’s a problem with the way mfks works. When trying to automatically determine filesystem sizes on loopback devices it makes a mistake. So for this we need to do a few things.
Find the partition beginning, ending, number of blocks, number of cylinders, and blocksize
fdisk -l -u /dev/loop0 Disk /dev/loop0: 10.7 GB, 10737418240 bytes 255 heads, 63 sectors/track, 1305 cylinders, total 20971520 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/loop0p1 * 63 20964824 10482381 83 Linux
Create a new loopback device for the partition. We do this by calculating the beginning of the partition x blocksize
In this case that’s 512 * 63 (actually in most cases thats what it is)
losetup -fv -o $((512 * 63)) newimage.raw Loop device is /dev/loop1
Remember those numbers we grabbed earlier using fdisk? Plunk them into this formula. For our example:
( END – START ) x Units / Block Size
If you don’t know the block size use 4096. That’s “standard” and usually the size configured on most ext2/3 filesystems.
So for us it’s this:
echo $(((20964824 - 63) * 512 / 4096 ))
This gives is the number of blocks we need to use in our next command, which is used to create a filesystem with a blocksize of 4096 on /dev/loop1 of block count 2620595. You have to specify the blocksize, otherwise mkfs will try and automatically determine a bunch of things for you which will just break things.
mkfs.ext3 -b 4096 /dev/loop1 2620595
3) Copy & Prepare New Root Filesystem
You can now mount this newly created filesystem somewhere and copy a root filesystem into it. If that filesystem happens to be a Xen image from Amazon, you can use that.
mkdir -p /mnt/loop/1 mount -t ext3 /dev/loop1 /mnt/loop/1 cp -a /some/root/filesystem/* /mnt/loop/1/
Xen virtual machines run with a special kernel that can run under KVM using Xenner, but not other platforms like VirtualBox, so we’re going to copy a real kernel in there. You can use one from another linux system if you want, it will work fine, but you should use one that has the modules required by your virtualization platform. We already have a KVM tuned kernel and initrd available so we’re going to use those.
Note: If you’re going to just copy in the initrd and kernel then make sure the initrd includes all of the modules required to boot your machine.
cp -r /some/boot/filesystem/* /mnt/loop/1/boot/
You should now see a the kernel, initrd and the grub directory in there.
Edit the menu.lst and make sure the root= is set to /dev/sda1
vim /mnt/loop/1/boot/grub/menu.lst
Edit the /etc/fstab in your mounted vm
vim /mnt/loop/1/etc/fstab
Because amazon’s best practices involve setting a random root password, which gets overridden at start time, you’ll have to solve that little problem.
chroot /mnt/loop/1 mv /etc/rc.local /etc/rc.local-old passwd root exit
5) Setup Grub on the New Drive
Now unmount /mnt/loop/1 and delete the loopback device for the partition (the one with the offset) so we can setup the bootloader. Grub complains about installing the MBR code when the loopback device is still active on the partition. Leave the loopback device for the entire drive. We’ll need that to get some numbers from fdisk.
umount /mnt/loop/1 losetup -d /mnt/loop1
fdisk -l -u /dev/loop0 Disk /dev/loop0: 10.7 GB, 10737418240 bytes 255 heads, 63 sectors/track, 1305 cylinders, total 20971520 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/loop0p1 * 63 20964824 10482381 83 Linux
Make a note of the numbers that were presented here. We’ll need the following to setup grub
- Cylinders : 1305
- Heads : 255
- Sectors / Track : 63
These numbers may be different for you depending on the size of partition you created, or a whole bunch of other variables. It’s important to remember these values because we’ll need them for our next step, which is to setup grub.
The following lists the set of commands required to setup the bootloader on a file backed disk over a loopback device.
grub --device-map=/dev/null device (hd0) /images/newimage.raw geometry (hd0) 1305 255 63 root (hd0,0) setup (hd0)
Here’s what that looks like in the grub dialogue:
grub --device-map=/dev/null Probing devices to guess BIOS drives. This may take a long time. Unknown partition table signature [ Minimal BASH-like line editing is supported. For the first word, TAB lists possible command completions. Anywhere else TAB lists the possible completions of a device/filename. ] grub> device (hd0) /images/newimage.raw device (hd0) /images/newimage.raw grub> geometry (hd0) 1305 255 63 geometry (hd0) 1305 255 63 grub> root (hd0,0) grub> setup (hd0) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 17 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd0) (hd0)1+17 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded Done. grub>quit
Conclusion
Yay! All you need to do now is delete all those loopback devices attached to your file, and boot it up in either KVM or VirtualBox
Hope you found that useful.


Nice tutorial!
I’ve taken the liberty of advertising for it in http://forums.meulie.net/viewforum.php?f=43 & http://forums.meulie.net/viewforum.php?f=79