In order to enable deployment of preconfigured environments or to scale your IAAS workloads you may need to clone your virtual machines. The process normally involves removing computer-specific information such as device drivers, administrator account and the computer security identifier (SID) from the machine, capturing the VM image and then using this image when provisioning new VM instances.
Removing computer-specific information
The first step depends on the operating system as you use OS specific tools to set your machine to the generalized state.
Windows
On Windows, run Sysprep to clean up system identity and put it into Out-of-Box experience
state.
%WINDIR%\system32\sysprep\sysprep.exe /generalize /shutdown /oobe
When it's done it's going to shut down the machine.
Linux
On Linux, run the following command on Azure agent that's going to remove machine and user specific configuration:
sudo waagent -deprovision+user -force
Then exit
the SSH session.
Generalizing Azure VM
The next step is to deallocate the VM and set its status to Generalized
:
Stop-AzureRmVM -Name Win01 -ResourceGroupName TestCloneVM -Force
Set-AzureRmVM -Name Win01 -ResourceGroupName TestCloneVM -Generalized
This is the Azure setting that is not OS specific.
Capturing the VM image
This step depends on the type of storage used for the VM disks.
Managed disks
If you use managed storage then you can directly create an Image resource consisting of disks that are attached to the machine.
New-AzureRmResourceGroup -Name TestImages -Location 'west europe'
$vm = Get-AzureRmVM -ResourceGroupName TestCloneVM -Name Win01
$imageConfig = New-AzureRmImageConfig -Location 'west europe' -SourceVirtualMachineId $vm.Id
New-AzureRmImage -Image $imageConfig -ImageName WinVM -ResourceGroupName TestImages
It creates a fully managed image:
$winImage = Get-AzureRmImage -ResourceGroupName TestImages -ImageName WinVM
$winImage.StorageProfile.OsDisk
OsType : Windows
OsState : Generalized
Snapshot :
ManagedDisk : Microsoft.Azure.Management.Compute.Models.SubResource
BlobUri :
Caching : ReadWrite
DiskSizeGB : 128
Notice that BlobUri
contains no value. You can delete the original managed disk and use this image to provision new VMs.
Unmanaged disks
If you use unmanaged disks you can save the image in the same storage account that is used for VM VHDs:
Save-AzureRmVMImage -ResourceGroupName TestCloneLinuxVM -Name Lin01 -DestinationContainerName vm-images -VHDNamePrefix LinVM
It's going to store the image under the predefined path system/Microsoft.Compute/Images
, e.g.: https://<account>.blob.core.windows.net/system/Microsoft.Compute/Images/vm-images/LinVM-osDisk.be6421b7-256f-4b34-b3ba-1d7bb54d4ae2.vhd
.
It's also going to generate an ARM template that can be used to provision VMs from this image.
Alternately, you may want to create an Image resource with New-AzureRmImageConfig
and New-AzureRmImage
just like you do for managed disks. In this case the Image resource will use the same VHDs that were part of the original VM:
$linuxImage = Get-AzureRmImage -ResourceGroupName TestImages -ImageName LinVM
$linuxImage.StorageProfile.OsDisk
OsType : Linux
OsState : Generalized
Snapshot :
ManagedDisk :
BlobUri : https://<account>.blob.core.windows.net/vhds/Lin01OsDisk.vhd
Caching : ReadWrite
DiskSizeGB : 128
It's also possible to create Image resources from multiple arbitrary VHDs (OS and data disks) as shown here. So you can turn images captured with Save-AzureRmVMImage
into proper Image resources.
Creating VMs from custom images
If you want to create a VM from an Image resource you need to specify it when setting up the VM configuration:
$image = Get-AzureRmImage -ResourceGroupName $ImageResourceGroupName -ImageName $ImageName
$vm = Set-AzureRmVMSourceImage `
-VM $vm `
-Id $image.Id
Then you use FromImage
option when configuring the OS disk:
$osDiskName = $VMName + 'OsDisk'
$vm = Set-AzureRmVMOSDisk `
-VM $vm `
-Name $osDiskName `
-DiskSizeInGB 128 `
-CreateOption FromImage `
-Caching ReadWrite `
-StorageAccountType StandardLRS
If you want to go with unmanaged disks you can specify the path where the VHD will be stored:
$storageAccount = Get-AzureRmStorageAccount -ResourceGroupName $StorageAccountResourceGroupName -Name $StorageAccountName
$blobEndpoint = $storageAccount.PrimaryEndpoints.Blob.ToString()
$osDiskName = $VMName + 'OsDisk'
$osDiskUri = $blobEndpoint + "vhds/" + $osDiskName + ".vhd"
$vm = Set-AzureRmVMOSDisk `
-VM $vm `
-Name $osDiskName `
-DiskSizeInGB 128 `
-CreateOption FromImage `
-Caching ReadWrite `
-VhdUri $osDiskUri
If you want to use arbitrary VHD images captured with Save-AzureRmVMImage
you can do it directly with Set-AzureRmVMOSDisk
without having to call Set-AzureRmVMSourceImage
:
$vm = Set-AzureRmVMOSDisk `
-VM $vm `
-Name $osDiskName `
-SourceImageUri $SourceImageUri `
-Linux `
-VhdUri $osDiskUri `
-DiskSizeInGB 128 `
-CreateOption FromImage `
-Caching ReadWrite
$SourceImageUri
is the path to your image, e.g. https://<account>.blob.core.windows.net/system/Microsoft.Compute/Images/vm-images/LinVM-osDisk.be6421b7-256f-4b34-b3ba-1d7bb54d4ae2.vhd
. And VhdUri
is the path to the new unmanaged OS disk of the provisioned VM.
Below you can find links to PowerShell scripts that can be used to create VMs from different types of custom images:
- New Linux VM with a managed OS disk from a generalized custom Image
- New Linux VM with an unmanaged OS disk from a generalized VHD
- New Linux VM with an unmanaged OS disk from a gallary image
- New Windows VM with a managed disk from a gallary image