In my last post we talked about moving resources between gesource groups in Azure Resource Manager (ARM). But what if you are not yet using Azure Resource Manager, and instead is stuck on Azure Service Management (ASM), or as Microsoft tend to call it: Azure Classic?
Well, you have some different options.
- Azure Migration tool
- 3rd party tools like Double-Take Move from Vision Solutions
- ASM2ARM – a collection of script to perform migraitons, developed by Fullscale180
ASM2ARM migrates 1 VM at a time, offline. migAz can migrate all your VMs at once, but also offline. Both tools copies data to new storage accounts, which can be both quick and slow. We’ve often seen speeds of 1 GB per minute, but also way faster copies.
Double-Take Move will do an online replication of data, between a source VM and destination VM. When replication is done, you’ll do a cutover which shuts down the source while replicating the last few bits, and starts the destination server. Only downtime is the “restart”, and it’s easy to plan the migrations as you have to do the cutover yourself. It’s not limited to Azure though, it can migrate from pretty much any platform to any platform.
We’ve used it a lot when migrating to Hyper-V or Azure, but it does come with a cost. Before Microsoft released the Azure Migration tool, we used DT Move to migrate customers from their own ASM subscriptions to CSP based ARM subscriptions.
For quite a while Microsoft has been working on a migration tool. A couple of weeks ago that tool was released to GA after a period of testing. This tool will do an online migration, no downtime, for free. Hard to beat, right? Of course it is, which is why I’ll focus on this tool for now.
Preparing for migration
There is some limitations to be aware of. The tool does not support:
- VPN Gateways
- Multiple subnets per VM
- VMs with Autoscale
- Multiple Availability Sets in the same Cloud Service
- A mix of single instance VMs, and VMs in Availability Sets
- If you have Azure IaaS Backup configured for VMs
And more.. These are just the primary blockers I’ve seen so far. A complete list can be found here.
I have a simple scenario to show the migration experience:
- 1 virtual network
- 3 VMs in 1 Cloud Service
- 2 of them in an Availability Sets
- 1 of them with no Availability Set configured
Remove the blockers
Do you see any blockers in the above scenario? You should, if you read the list of unsupported configurations ;-) I have a mix of single instance VMs and VMs in Availability Sets. No worries though, there are ways to fix that. Basically we have to either move the 2 VMs to a new cloud service, or the 1 VM. Moving them involves downtime on 1 VM at a time. Which one should I choose then? It all depends on your configuration, but I would argue that to have the least disruption on your services, you should move the 2 VMs in Availability Set. Why? Because services that are configured in Availability Sets should be able to have 1 VM offline and still work. So moving 1 VM at a time should be possible, while still having the service online. No need for late night maintenance windows or such.
It’s actually quite easy to move VMs. Using the Export-AzureVM and Import-AzureVM PowerShell cmdlets, we can do it pretty quick, without having to reconfigure everything. First of, let’s get define some variables:
$currentCloudServiceName = "puzzlesmove" #Name of the Cloud Service to move from $newCloudServiceName = "puzzlesnew" #Name of the Cloud Service to move to $storageAccount = "puzzlesmove" #Storage Account name $subscriptionName = "Demo" #Subscription name $vmNameToMove = "DC1" #VM to move $savedVMStateFilePath = "C:\Temp\DC1.xml" #A path to save the configuration file $vnetName = "puzzlesmove" #Name of virtual network
Make sure the destination Cloud Service is created before you migrate! Now let’s set the storage account we want to work with, and then select our subscription:
Set-AzureSubscription -SubscriptionName $subscriptionName -CurrentStorageAccountName $storageAccount Select-AzureSubscription $subscriptionName
And then export our VM configuration. I usually use Get-AzureVM to make sure it’s the correct VM I’m working with:
Get-AzureVM -ServiceName $currentCloudServiceName -Name $vmNameToMove Export-AzureVM -ServiceName $currentCloudServiceName -Name $vmNameToMove -path $savedVMStateFilePath
In case you want to edit your VM configuration – maybe change name of the Availability Set og resize it – you can do so in notepad or whatever editor you use. But be careful!
Now we need to stop the VM, and remove it. Don’t worry, this will not delete the virtual disks!
Stop-AzureVM -ServiceName $currentCloudServiceName -Name $vmNameToMove Remove-AzureVM -ServiceName $currentCloudServiceName -Name $vmNameToMove
Last, run Import-AzureVM to create the VM again. If you haven’t created the new Cloud Service, this command will fail.
Import-AzureVM -Path $savedVMStateFilePath | New-AzureVM -ServiceName $newCloudServiceName -VNetName $vnetName
Moving a VM like this takes about 5 minutes. If you access the service publicly, you will of course need to redirect that traffic to the new Cloud Service, before taking down the 2nd VM. If you get the following error:
Import-AzureVM -Path $savedVMStateFilePath | New-AzureVM -ServiceName $newCloudServiceName -VNetName $vnetName WARNING: VNetName, DnsSettings, DeploymentLabel or DeploymentName Name can only be specified on new deployments. New-AzureVM : ConflictError: A disk with name dc1-dc2-0-201607201151130916 is currently in use by virtual machine dc2 running within hosted service puzzlesmove, deployment dc1. OperationID : 'd680cabc1b7f09a0ae6a60f71d635afd' At line:1 char:46 + ... eFilePath | New-AzureVM -ServiceName $newCloudServiceName -VNetName $ ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [New-AzureVM], ComputeCloudException + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.ServiceManagement.IaaS.PersistentVMs.NewAzureVMCommand
Now that we have removed the blockers, we can start migrating our environment. It’s actually quite simple, and is done via PowerShell. First step is to register the migration resource provider with your subscription:
Register-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate Get-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate
Next, run Move-AzureVirtualNetwork to prepare the migration:
$vnetName = "puzzlesmove" Move-AzureVirtualNetwork -Prepare -VirtualNetworkName $vnetName
This step will check that your configuration is valid. In case it’s not, it will throw an error like this:
$vnetName = "puzzlesmove" Move-AzureVirtualNetwork -Prepare -VirtualNetworkName $vnetName Move-AzureVirtualNetwork : BadRequest : Migration is not supported for Deployment dc1 in HostedService puzzlesmove because it has VMs that are not part of the Availability Set even though the HostedService contains one. At line:1 char:1 + Move-AzureVirtualNetwork -Prepare -VirtualNetworkName $vnetName + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Move-AzureVirtualNetwork], ComputeCloudException + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.ServiceManagement.IaaS.Network.MoveVirtualNetworkCommand
Anyways, if you have done your homework, the command should just take a while to run, and then finish. After it completes, you should check Azure Resource Manager (portal.azure.com) to see if everything is configured correctly. Nothing is migrated until we commit! Let’s take a look at my resources:
See those resource groups named “-Migrated”? That’s our new resources. Now, in this scenario my vnet had the same name as my Cloud Service (the one with 1 VM left). Because of that Azure added an “s” to the resource group “puzzlesmoves-Migrated” for that Cloud Service, since a seperate resource group is created for the network, with the same name as my network. If we look closer at the “puzzlesnew-Migrated” resource group, we can see all the resources:
So we have our Availability Set, we have the VMs and their NICs. But hey, we also have Load Balancer with a Public IP assigned? That’s because in ASM a Cloud Service also contains a Load Balancer, a lot of people just never think of that. Anyways, all the rules for that Load Balancer is also migrated – except if you use ACLs on any of your endpoints!
The Public IP is the same as we had in ASM, and it will keep it’s *.cloudapp.net name too.
So this looks fine, let’s go ahead and commit it:
Move-AzureVirtualNetwork -Commit -VirtualNetworkName $vnetName
This can take a while too, just sit back and get a cup of tea (I don’t drink coffee – wierd for an IT guy, right?). When done, the VMs will be gone from ASM:
Great! Let’s move our Storage Account then. This is also done through PowerShell, but with the Move-AzureStorageAccount cmdlet:
$storageAccountName = "puzzlesmove" Move-AzureStorageAccount -Prepare -StorageAccountName $storageAccountName
Again, it’s a 3 step process. First prepare, then check if it looks good, an finally commit.
Move-AzureStorageAccount -Commit -StorageAccountName $storageAccountName
In case you want to abort any of these migrations after running the prepare command, you can always use -Abort instead of -Commit, like this:
Move-AzureVirtualNetwork -Abort -VirtualNetworkName $vnetName Move-AzureStorageAccount -Abort -StorageAccountName $storageAccountName
A last word…
While migrating an environment using the above process, I ran into a wierd issue. I was able to do the prepare step, but when I did a commit, I got this error:
Move-AzureVirtualNetwork : BadRequest : Migration is not supported for Virtual Network WAP because it has third party PaaS deployments.
I didn’t have any PaaS or third party resources, so I was a bit confused by that one. It turned out that it was because I had a VPN gateway attached to the network, though we hadn’t used VPN for the past 6 months..
No more words from me now, I hope this helps you getting away from the dark side of Azure :-)