Migrating Azure VMs to ARM/CSP using migAz

Server Hero
In this “how to” article, I’m going to show you how you can quickly and easily move Classic / Service Management / SM Azure IaaS virtual machine deployments to Azure Resource Manager / ARM in another subscription. For example, you can migrate virtual machines and their dependencies from direct/Open/EA Azure subscriptions to Cloud Solution Provider (CSP) subscriptions.
If you want to migrate Azure classic virtual machines to ARM in the same subscription, then have a look at Migrating Azure VMs from Classic Service Management to Resource Manager on Petri IT Knowledgebase.

The Challenge

If you were unsure after the recent Microsoft Worldwide Partner Conference (WPC), then let me be clear; CSP is Microsoft’s preferred way to sell cloud services (and more) via the Microsoft Partner Network. CSP offers quite a bit for partners and customers, because it gives them the billing the want/expect, with a built-in support program, and true OPEX flexibility.
The first challenge with Azure in CSP is that, unlike every other channel, it supports only Azure V2, otherwise known as Azure Resource Manager or ARM. The vast majority of previously deployed solutions are based on the older Azure V1, or Service Management or Classic resources. The second issue with CSP is that Microsoft has not provided any support migration path from other subscription types to CSP. Without a migration tool, this means that CSP will be limited to new installations that require little to no integration to any previously deployed resources.

The Solution

A Microsoft employee, Paulo Ramos (working as a Datacenter CoE Architect, I believe), has published an excellent open source migration solution on GitHub called migAz. The migAz solution will:

  1. Scan a classic Azure VM deployment in a source subscription.
  2. Create a JSON file of an ARM version of the deployment.
  3. Create a JSON file to allow migration of the virtual hard disks.
  4. Create an ARM deployment of the solution in a destination subscription, using the JSON file.
  5. Migrate the virtual hard disks to the destination subscription.

The source machines remain unchanged in the original subscription. This allows you to test out a migration, with minimal impact, before you make a commitment to switch over to the ARM / CSP subscription.
This all sounds like it’s going to be a messy experience; I can tell you that, after I tested migAz out, it’s actually a pretty clean solution that allows you to customize as much or as little as you want to. I think that migAz might be the way to get virtual machines moved into CSP subscriptions.
The disks of the source virtual machines are copies using a one-time-only snapshot. If customers are still using the source virtual machines after the copy, then data will be lost during the switchover. So you have a choice:

  • Turn off the virtual machines before the migration.
  • Migrate the running virtual machines, and synchronize data using a VNet-to-VNet VPN afterwards.
  • Rebuild any machines with data by hand, and synchronize data using a VNet-to-VNet VPN afterwards.

My Classic Deployment

I created a classic deployment of Azure virtual machines in the older Azure Management Portal in an Azure in Open subscription. This deployment was comprised of:

  • 3 virtual machines
  • A cloud service
  • A virtual network
  • An LRS storage account

The classic virtual machines before migration [Image Credit: Aidan Finn]
The classic virtual machines before migration [Image Credit: Aidan Finn]
The older management portal doesn’t do resource groups, so Azure created a messy collection of resource groups to store the classic resources.
The resource groups containing the classic resources [Image Credit: Aidan Finn]
The resource groups containing the classic resources [Image Credit: Aidan Finn]
I want to move this entire classic application deployment from Azure in Open to a single tidy resource group in my new Azure in CSP subscription (ARM).

Requirements

The solution is based on PowerShell so make sure that you have the latest versions of the Azure and AzureRM PowerShell modules.
You will also need to:

  • Get the credentials of your source Azure subscription, where the virtual machines are deployed as classic resources.
  • Record the credentials of your destination Azure subscription, where you want to redeploy your virtual machines as ARM resources.
  • Download and extract the migAz released ZIP file.

Export the JSON Files

In my example, I extracted the migAz files to C:\Temp\migAz. One of the resulting files is migAz.exe. Run this file (override Windows SmartScreen if you feel safe about it, if required). Do the following:

  1. Sign into your source Azure subscription.
  2. Select all of the resources that you want to migrate to your destination Azure subscription.
  3. Enter a path to store the exported JSON files.
  4. Click Export to start the job.

Export your classic Azure virtual machines as ARM JSON files [Image Credit: Aidan Finn]
Export your classic Azure virtual machines as ARM JSON files [Image Credit: Aidan Finn]

The JSON Files

The job will take a few minutes to run. A pair of JSON files were created for me:

  • copyblobdetails.json: This file stores the details of the virtual hard disk blobs that must be migrated. Be careful with this file because it contains storage account access keys that can be used remotely.
  • export.json: This file is a design of your virtual machine deployment in an ARM environment.

The exported JSON files [Image Credit: Aidan Finn]
The exported JSON files [Image Credit: Aidan Finn]
The export.json file is quite an interesting read. For example, you can see how a cloud service with endpoints will be re-deployed as an Azure ARM load balancer with load balancing and NAT rules. If you want, you can modify this JSON file to change the deployment or to add extra resources. In my case, I made no changes, but I could have configured the new deployment to use a different network address so that I could have parallel connections to both the classic and ARM deployments during a pre-switch testing phase.
The classic Azure cloud service is converted in an ARM load balancer [Image Credit: Aidan Finn]
The classic Azure cloud service is converted in an ARM load balancer [Image Credit: Aidan Finn]

Create the ARM Deployment

One of the very cool things about ARM is that you can very easily and quickly deploy a complex service with a single line of PowerShell and a JSON file. We have a JSON file (export.json) and we have installed the latest version of PowerShell …
Launch PowerShell and log into your destination Azure subscription using the Azure ARM module:

Login-AzureRmAccount

Check your available subscriptions:

Get-AzureRmSubscription

Select your desired subscription with:

Select-AzureRmSubscription -SubscriptionId “<The ID of the destination subscription>”

You will need to create a resource group to store the migrated resources. You can do this using PowerShell:

New-AzureRMResourceGroup -Name “<Name of the new resource group>” -Location “<Name of the desired Azure region>”

Now you will create a new ARM deployment from export.json:

New-AzureRMResourceGroupDeployment -Name “<Desired name of the new deployemnt>” -ResourceGroupName “<Name of the new resource group>” -TemplateFile “<Path to export.json>” -Verbose

Site back and relax; Azure will start to deploy your virtual machines and all of their dependencies … except for the virtual hard disks! This will result in a warning, as you can see below.

Importing the service into Azure in ARM / CSP [Image Credit: Aidan Finn]
Importing the service into Azure in ARM / CSP [Image Credit: Aidan Finn]

Copy Virtual Hard Disks

The next step will be to copy the virtual hard disks from the source subscription to a shiny, new, but empty storage account in the destination Azure subscription. Don’t worry; you do not need to download and upload huge files. We can use Azure’s APIs to do a copy within the Azure network; migAz includes a script to do this using the information stored in copyblobdetails.json.
Browse to the extracted location of migAz in the PowerShell window and run BlobCopy.ps1 (you will need to allow unsigned scripts to run):

.\BlobCopy.ps1 -ResourcegroupName “<Name of the new resource group>”  -DetailsFilePath "<Path to copyblobdetails.json>" -StartType StartBlobCopy

This script will kick off copy jobs that run in the background. You can monitor the progress of the jobs by running:

.\BlobCopy.ps1 -ResourcegroupName “<Name of the new resource group>”  -DetailsFilePath "<Path to copyblobdetails.json>" -StartType MonitorBlobCopy

In my case, the copy was completed faster than I could type the monitor command!

Fix Up Virtual Machines

You should re-run the New-AzureRMResourceGroupDeployment cmdlet to fix up the virtual machines with the freshly imported virtual hard disks:

New-AzureRMResourceGroupDeployment -Name “<Desired name of the new deployemnt>” -ResourceGroupName “<Name of the new resource group>” -TemplateFile “<Path to export.json>” –Verbose
The virtual machine migration to ARM / CSP is complete [Image Credit: Aidan Finn]
The virtual machine migration to ARM / CSP is complete [Image Credit: Aidan Finn]

Test & Check

You can now use PowerShell and the Azure Portal to inspect and test the deployment of your virtual machines in Azure. The virtual machines are running in your ARM / CSP subscription, but no clients should be accessing them yet.
When I log into the Azure Portal, I can see that my previously messy service is now contained within a single (highlighted) resource group. An availability set and a load balancer was created instead of a cloud service.

The migrated resources in an ARM resource group [Image Credit: Aidan Finn]
The migrated resources in an ARM resource group [Image Credit: Aidan Finn]
I can verify that my endpoints have been converted into NAT rules in the load balancer.
NAT rules in the Azure ARM load balancer [Image Credit: Aidan Finn]
NAT rules in the Azure ARM load balancer [Image Credit: Aidan Finn]
The old service was a very classic deployment:

  • The new load balancer is created with a dynamic public IP address, even though I had reserved the cloud service IP address. I should reconfigure this as a static IP address.
  • There are no network security groups. I should changing this, and consider the deployment of a DMZ.
  • There is no migration of the Azure Backup Vault. I should deploy a Recovery Services Vault and backup my new virtual machines.
  • I can review and tidy up the NAT rules.


Once I am ready to switch over, I should either create a VPN/ExpressRoute connection and/or change my public IP addresses to start using the public IP address of the Azure load balancer.
If I am not happy about switching over, I can leave everything unchanged and stick with the classic deployment in the source Azure subscription – I can delete the ARM resources in the destination subscription without users noticing.