Posts Tagged: Xen


20
Oct 09

How to move a Virtual Machine From EC2 to VirtualBox or KVM

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.raw

Partition 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.