Xen to KVM: How to convert when xen is dead
Greetings internet wayfarer. If you have ended up here because your Xen server took a poop and you need to get those old para-virtualized Xen VM’s running on a KVM server. Well congrats, you have arrived. I just dealt with that very same problem. It’s a doozy, but fear not: There is a solution. It can be done.
Like you, I had an old xen server that died, and a running KVM server that I wanted to use to get the servers that were on the xen host running again. I ran into the problem though that most of the guides/information about converting from Xen to KVM assume a running Xen server, which did me no good.
So first of all, you’ll need your xen .img files. You’ll also want to keep track of the xen vm definition xml file. You wont need it for this conversion process, but it is good to reference to take care of things like MAC addresses after conversion is done. Get those .img files moved over to your KVM server. I’ll not go into details on the how, I’m sure you have that taken care of.
- You’ll need a non Xen Kernel in your VM’s
- First step in this is to assess your VM’s hard drive situation, we can do that using fdisk. For the purposes of this guide let’s assume vm stores are under /images, and we’re working on a server named… *gasp* Server1.
- Next up on the agenda is to create a temporary mount that can be used as a target to chroot into. That is fairly easy.
After that it’s simple as mounting the volumn groups that are important. In the very least you’ll need the root partition, and the boot partition.- Finally we’ll need to bind /dev
- The final step is to simply use the package manager of the VM to install a standard kernel.
- Convert!
- This is the easy part, you’ll need a tool called “virt-v2v”
- After that’s done, you just need to point the conversion tool at a disk image, rather than at a remote server. This is where most of the information I found online fell short. virt-v2v has a huge amount of options, so sorting through the right way to use it can be pretty rough. Anyway, I’ve found that this works:
- You will end up with an xml file that looks something like this:
Start the new VM!
This part felt pretty daunting to me at first, but there are a few tricks that can make your life much easier. Tricks that unless you have run into this situation before you may not have known about. Essentially what we’re going to do is mount the disk image on a loop device, chroot into said disk image, and download the kernel using the systems native package manager.
fdisk -l /images/server1.img
This should give you some simple fdisk output.
Disk server1.domain1.com.img: 8388 MB, 8388608000 bytes, 16384000 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x000359ed Device Boot Start End Blocks Id System server1.domain1.com.img1 * 2048 1026047 512000 83 Linux server1.domain1.com.img2 1026048 16383999 7678976 8e Linux LVM
You’ll note a fairly simple disk configuration in this case, a standard linux partition set as the boot device, and an LVM Volume for the rest of the drive. The LVM part can be a bit tricky, which is why I’ve included it. If you don’t have an LVM setup on your VM, use the “offset” method that will be used for mounting the boot device, for both partitions. Easy peasy.
mkdir /mnt/server1
For LVM devices:
We’ll be using a little tool called kpartx to map the .img file to to loop devices, which will allow us to do some magic with the LVM stuff.
kpartx -av /images/server1.img
Once the mapping is done your virtual drives will show up under /dev/mapper/ as loop devices, and can be accessed like normal hard drives…which means for LVM stuff…You can import them into your existing LVM config!
vgscan
This will show you a list of Volumn groups that were found, even existing ones. It should look something like this:
Reading all physical volumes. This may take a while... Found volume group "vg_server1" using metadata type lvm2 Found volume group "vg_imageStore" using metadata type lvm2 Found volume group "centos" using metadata type lvm2
In this case, vg_server1 is your virtual volumn group, and the other two are those that I have on the host system.
mount /dev/vg_server1/lv_root /mnt/server1
Now, your boot device should have also been mapped to a /dev/mapper/loop device, but we’re going to pretend that’s not the case, because there is a simpler way in my opinion. For the boot device, or for all drives if you don’t have LVM, you can simply mount directly through loop using the offset option. It’s pretty cool…But does require a little math. You have to multiply the starting point of the partition, against the size of the Unit. Going back to our fdisk from above:
Disk server1.domain1.com.img: 8388 MB, 8388608000 bytes, 16384000 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x000359ed Device Boot Start End Blocks Id System server1.domain1.com.img1 * 2048 1026047 512000 83 Linux server1.domain1.com.img2 1026048 16383999 7678976 8e Linux LVM
That’s Unit size of 512, and starting point of 2048. Which gives us an offset of 1048576.
so to mount the boot device we would simply use mount like so:
mount -t auto -o loop,offset=1048576 /images/server1.img /mnt/server1/boot
Originally when I was going through this, I thought I was done before this point. I got things mounted. I was good to go.. so I issued a simply chroot /mnt/server1, and yum install kernel, and…. Yum apparently relies on /dev/urandom…Who knew?
Anyway, the /dev/urandom issue is a simple fix. we’re going to bind mount /dev/ to /mnt/server1/dev…LIKE SO!
mount --bind /dev /mnt/server1/dev
Now you are good to go.
That is as simple as the following:
chroot /mnt/server1 yum -y install kernel exit
You are done with step 1! good job, before we move on though…Let’s talk cleanup:
umount /mnt/server1/boot umount /mnt/server1/dev umount /mnt/server1 vgchange -an vg_server1 vgremove my_volume_group kpartx -d /images/server1.img
In order that is: unmounting the three partitions, deactivating volume group, removing the volume group from your local VG store, and then deleting the link to the loop devices to the server1.img file.
yum -y install virt-v2v
virt-v2v -i disk /images/server1.img -o local -os /images/
That should take the xen server1.img, and convert it to a kvm file, as well as generating some basic KVM config XML in the /images folder. It will name the new file something different than the original image file. Probably server1-sda.img.
<?xml version='1.0' encoding='utf-8'?> <domain type='kvm'> <name>Server1</name> <memory unit='KiB'>2097152</memory> <currentMemory unit='KiB'>2097152</currentMemory> <vcpu>1</vcpu> <os> <type arch='x86_64'>hvm</type> </os> <features> <acpi/> <apic/> </features> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <disk type='file' device='disk'> <driver name='qemu' type='raw' cache='none'/> <source file='/images/server1-sda'/> <target dev='vda' bus='virtio'/> </disk> <interface type='network'> <source network='default'/> <model type='virtio'/> </interface> <video type='qxl' ram='65536' heads='1'/> <graphics type='vnc' autoport='yes' port='-1'/> <input type='tablet' bus='usb'/> <input type='mouse' bus='ps2'/> <console type='pty'/> </devices> </domain>
NOTE: Your config will depend a lot on how your other VM’s are configured, So I recomend looking at an existing KVM VM, and adding any changes that are necessary. Especially around the network interface. Very likely you will need to modify that to be in line with the network interface. It may also be a good idea to copy the MAC address from the old xen config file and add it to the interface for the new KVM VM.
virsh create /images/server1.xml
NOTE: It may be a good idea to first move your xml file to wherever your existing KVM xml files are located. That is slightly outside the realm of this guide though.
That should be about it! you should be in good shape.