Migrating a non-HyperV VM to Azure

Let’s have some fun in this post moving a virtual machine from VirtualBox on MacOS to Azure. This can be a little tricky because not only do you have to prep the VM as you normally would for Azure but you also have to package up the HyperV modules so you can be used at boot time once moved. Personally, I would recommend Infrastructre as Code (IaC) and configuration management software typically for this kind of thing, however, sometimes that’s not an option so in this post we’ll look at moving a VM from MacOS (no HyperV) to Azure (HyperV) and what it takes to get there.

Problem

Migrating an existing non-HyperV VM to Azure. For this we need to prep the VM and install the HyperV modules in the initrd.

Solution

Microsoft provides a good starting point for migrating VMs to Azure in their documentation with Create a Linux VM from a custom disk with the Azure CLI. This document was my starting point but the really important section of the page to review is the Prepare the VM section. This lists the most popular distros and how to go about preparing for a move to Azure. In my case I was moving an Oracle 7.7 VM from VirtualBox so I will cover the basic steps I used based on Prepare an Oracle Linux virtual machine from Azure. This page covers all the essential steps… mostly (we’ll cover the gaps below)… but the ordering of the steps is misleading and caused me a few hours so I thought I’d rewrite the steps here for anyone who doesn’t want to waste their time :smiley:.

NOTE: It should also be noted that Oracle Enterprise Linux has the HyperV modules included in the distro which means I was able to bundle them into my initrd using the process shown below. In some cases you will need to download and install the Linux Integration Services package from Microsoft to get the modules you need for HyperV.

First, it should be noted that the page assumes you are currently using HyperV which in the VirtualBox case we are not. This would also apply to VMWare VMs as well (ie. no HyperV). This means that we are going to need to add some HyperV modules to the boot process so that when we get to Azure the VM will have the necessary modules to boot on a HyperV hypervisor.

Before we get started you should do a yum update. This is also important because we are going to create a new initrd and if you rebuild the initrd before you install the updates you have the potential to get a new kernel version which would mean the initrd changes wouldn’t be loaded with the new kernel. So in summary unless you have a good reason not to run update just do it.

>> sudo yum -y update
>> reboot

The first thing we’ll do after than is rebuild the initrd filesystem and include the HyperV modules we’ll need in Azure. Modify /etc/dracut.conf and under the add_drivers line we’ll add the HyperV modules.

>> echo "add_drivers+=\"hv_vmbus hv_netvsc hv_storvsc hv_balloon hv_utils hid_hyperv hyperv_keyboard hyperv_fb\"" >> /etc/dracut.conf
>> sudo dracut -f -v

At this point you’ll have a new initrd that contains the HyperV modules. You can check this with lsinitrd.

>> lsinitrd | grep hv
drwxr-xr-x   2 root     root            0 Oct  9 19:49 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/hv
-rw-r--r--   1 root     root        10296 Sep 19 20:47 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/hv/hv_balloon.ko.xz
-rw-r--r--   1 root     root        12588 Sep 19 20:47 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/hv/hv_utils.ko.xz
-rw-r--r--   1 root     root        32936 Sep 19 20:47 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/hv/hv_vmbus.ko.xz
-rw-r--r--   1 root     root        31184 Sep 19 20:47 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/net/hyperv/hv_netvsc.ko.xz
-rw-r--r--   1 root     root         9604 Sep 19 20:47 usr/lib/modules/4.14.35-1902.5.2.2.el7uek.x86_64/kernel/drivers/scsi/hv_storvsc.ko.xz

At this point you can start following Prepare an Oracle Linux virtual machine for Azure. In my case I was using the Oracle Linux 7.0+ instructions. There are 2 parts to the instructions that weren’t clear so I’ll give my .02 there.

Step 9 calls for modifying /etc/default/grub. Just make sure your GRUB_CMDLINE_LINUX is what is documented. You can remove the other settings in that particular line.

Here is mine after the changes were made.

GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="rootdelay=300 console=ttyS0 earlyprintk=ttyS0 net.ifnames=0"
GRUB_DISABLE_RECOVERY="true"

These settings will ensure you can connect to the serial port from Azure (not Azure Government but hopefully soon :wink:).

Step 12 instructs you to install the WALinuxAgent and enable it. This is not strictly necessary but is definitely recommended. However, you have to enable the [ol7_addons] section in /etc/yum.repos.d/oracle-linux-ol7.repo file by adding enabled=1.

[ol7_addons]
name=Oracle Linux $releasever Add ons ($basearch)
baseurl=https://yum$ociregion.oracle.com/repo/OracleLinux/OL7/addons/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1

After the steps to prepare the VM have been completed you should reboot the VM to ensure all your changes didn’t accidentally break something, otherwise you are now ready to upload to Azure and attach to a VM using the instructions found at Create a Linux VM from a custom disk with Azure CLI. These instructions worked out of the box so I won’t repeat them here.

At this point you should have a working VM in Azure that was migrated from your non-HyperV environment. Good Luck!!