In the last few Coffee Break posts we have been looking at virtual hard disks (VHDs) and virtual machines (VMs). Now let's combine the two in the cloud.
Coffee Break 11 – Provisioning - Using Microsoft Azure storage to keep VHDs and other useful stuff in the cloud
Provisioning a new instance of Microsoft Dynamics NAV is like putting individual bits together. In this Coffee Break post, we will prepare some of these bits by building a VHD up front and then upload it to Azure. Then every new virtual machine (VM) can pick a copy of this disk. A VHD like this can contain anything such as the Microsoft Dynamics NAV product DVD, application objects, add-on databases, documents, and so on. And we can save a bit of time and bandwidth compared to uploading a new DVD, for example, every time we provision a new VM in the cloud.
The customer is frequently creating new VMs. And every new VM they create will need access to common data, such as the Microsoft Dynamics NAV product DVD.
1 VHD (local) and 1 VM (In Azure):
Get the VHD to the VM
Once we have a VHD (locally) and a VM in Azure (whether this was created manually or via PowerShell), let's combine the two. First, upload the VHD to Azure. Connect your ISE PowerShell environment to your Azure subscription:
Create a new storage account to hold our VHD:
$SourceStorageAccount = "mysharedstuff"
First test that the storage name is actually available:
Test-AzureName -Storage $SourceStorageAccount
If it is (the line above returns False), then create it:
New-AzureStorageAccount -StorageAccountName $SourceStorageAccount -Location "West Europe"
Optionally we can add containers to this storage, just to keep things organized. First, let's create a context that includes access information for our new storage:
$Key = (Get-AzureStorageKey -StorageAccountName $SourceStorageAccount).Primary
$Context = New-AzureStorageContext -StorageAccountName $SourceStorageAccount -StorageAccountKey $Key
This $Context variable gives us access to the storage, and is one we will use a couple of times.
Create a container in our storage to store vhds:
New-AzureStorageContainer -Context $Context -Name vhds
Upload the VHD
Let’s say you have a local VHD here: C:\temp\mydisctest.vhd. Then copy that up to your storage:
Add-Azurevhd -LocalFilePath C:\temp\mydisctest.vhd -Destination "https://$SourceStorageAccount.blob.core.windows.net/vhds/mydisk.vhd"
If you get this error: "The process cannot access the file 'C:\temp\mydisctest.vhd' because it is being used by another process." then make sure that the disk is not already mounted to your local machine. Note that if you happen to double-click on the VHD, Windows may automatically mount it. You can dismount it like this:
Dismount-VHD -Path C:\temp\mydisctest.vhd
(side note:) If you should ever need to copy it back, use Save-AzureVhd.
The Add-Azurevhd cmdlet does a clever copy by checking that this is a valid VHD, and by copying only actual data. So if the disk itself is 3GB but is only 5% full, then only a file the size of the 5% will actually be copied.
Make a copy
Every time we want a new disk, then we can make a new copy of this VHD, rather than attaching it directly in which case we could only use it for one VM. First create a new container for our copy. This container could relate somehow to the VM that we will be attaching the VHD to:
New-AzureStorageContainer -Context $Context -Name myvm
Then copy mydisk.vdh from vhds to myvm:
$SourceURI = "https://$SourceStorageAccount.blob.core.windows.net/vhds/mydisk.vhd"
$State = Start-AzureStorageBlobCopy -AbsoluteUri $SourceURI -DestContainer myvm -DestBlob NewVHD.vhd -Context $Context
This will start an asynchronous copy. To check status before using the copy:
$state | Get-AzureStorageBlobCopyState
Get it together
Now we have a fresh copy of the VHD in Azure, let’s attach it to a VM, using the cmdlet Add-AzureDataDisk. The two main ways we can use this cmdlet are:
- ImportFrom – to import an existing VHD - the one we will use here
- CreateNew – to create a new raw disk
The syntax of the cmdlet is:
$vm | Add-AzureDataDisk | Update-AzureVM
So, we need to get the VM, then pipe it through in that way. First check that you have the right VM. See which ones you have available:
Then pick one:
$VM = get-azurevm -ServiceName mytestserviceabcdef -Name NAVPC
Check that you still have the location for your VHD and then store that in another new variable:
$NewVHD = "https://$SourceStorageAccount.blob.core.windows.net/myvm/NewVHD.vhd"
Then put $VM through the pipe (or edit the line above if you want to have it all in just one line):
$VM | Add-AzureDataDisk -ImportFrom -DiskLabel "MyStuff" -MediaLocation $NewVHD -LUN 3 | Update-AzureVM
If you want to watch as it is happening, connect (RDC) to one of your Azure VMs and run File Explorer. Leave that in the background – it will update automatically and you can see when the disk is added. The disk is ready to use, and the files you put on it back when the disk was still on your local machine, are available now in your VM.
To remove it again, run this:
$VM | Remove-AzureDataDisk -LUN 3 -DeleteVHD | Update-AzureVM
Check what disks (if any) are still attached:
$VM | Get-AzureDataDisk
If you attach and then detach the disk, Azure may still hold a lease on this disk, and it may not be free to use yet or even to be deleted. This is the error you may get when trying to attach the disk again or delete it: "The MyDisk VHD is already registered with image repository as the resource with ID XYZ". In this case we may not be able to delete the disk automatically, which is why in the example above, if we remove the disk, then delete the disk as part of that operation.
So, just to avoid problems like this: When we detach a disk, then just to keep things clean, use -DeleteVHD to remove the disk completely.
Jasminka Thunes, Escalation Engineer Dynamics NAV EMEA
Lars Lohndorf-Larsen, Escalation Engineer Dynamics NAV EMEA
Bas Graaf, Senior Software Engineer Dynamics NAV