How to shrink a managed disk

Developer Support


In this post, App Dev Manager Mike Lapierre walks us through how to shrink an Azure managed disk.

Managed disks offer several benefits but are priced differently than their non-managed counterpart. With non-managed disks, even though you create a 128GB disk like several Azure gallery images do, you are just charged for the bytes you use (i.e. pages with data). For example, the standard Windows Server 2016 images uses roughly 13GB, so you’ll be charged for that size. Managed disks sizes are priced by tiers, so currently you’ll be charged at the S10/P10 (128GB) tier while the image would fit in a S4/P4 (32GB) or a S6/P6 (64GB) tier. Though you can easily increase the size of a managed disk from the portal, you cannot shrink it easily. Let’s look at how to shrink managed disks and get the most out of your Azure spend.

The steps to accomplish this are:

  1. Choose the best disk size
  2. Shrink the partition size in the VM
  3. Export the managed disk to a VHD
  4. Shrink the exported VHD
  5. Create a new managed disk from the VHD
  6. Create a new VM from the new managed disk
  7. Optionally cleanup the old resources

Let’s now go into the steps in details:

1. Choose the best disk size

Since disk sizes are charged to the rounded up nearest size, you should pick the best size accordingly. For example, if you choose 35GB, you’ll be charged for 64GB. Refer to this table for more details.

2. Shrink the partition size in the VM

One simple PowerShell to run inside the VM while it’s running (adjust the size accordingly):

Resize-Partition -DiskNumber 0 -PartitionNumber 1 -Size 32GB

3. Export the managed disk to a VHD

Make sure the VM is deallocated, and then run the following commands (adjust variables accordingly):

#Provide the subscription Id of the subscription where snapshot is created
$subscriptionId = "yourSubscriptionId"
#Provide the name of your resource group where snapshot is created
$resourceGroupName ="yourResourceGroupName"
#Provide the managed disk name
$managedDiskName = "yourManagedDiskName" 
#Provide Shared Access Signature (SAS) expiry duration in seconds e.g. 3600.
$sasExpiryDuration = "3600"
#Provide storage account name where you want to copy the snapshot. 
$storageAccountName = "yourstorageaccountName"
#Name of the storage container where the downloaded snapshot will be stored
$storageContainerName = "yourstoragecontainername"
#Provide the key of the storage account where you want to copy snapshot. 
$storageAccountKey = "yourStorageAccountKey"
#Provide the name of the VHD file to which snapshot will be copied.
$destinationVHDFileName = "yourvhdfilename"
#Logs in to the Azure Account
#Set the context to the subscription Id where Snapshot is created
Select-AzureRmSubscription -SubscriptionId $SubscriptionId
#Generate the SAS for the managed disk
$sas = Grant-AzureRmDiskAccess -ResourceGroupName $resourceGroupName -DiskName $managedDiskName -Access Read -DurationInSecond $sasExpiryDuration
#Create the context for the storage account which will be used to copy snapshot to the storage account 
$destinationContext = New-AzureStorageContext –StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
#Copy the snapshot to the storage account and wait for it to complete
Start-AzureStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $storageContainerName -DestContext $destinationContext -DestBlob $destinationVHDFileName
while(($state = Get-AzureStorageBlobCopyState -Context $destinationContext -Blob $destinationVHDFileName -Container $storageContainerName).Status -ne "Success") { $state; Start-Sleep -Seconds 5 }

4. Shrink the exported VHD

This is a tough one, it’s basically not supported to shrink a VHD on Azure. I always thrive to do things in the most efficient way possible. Knowing that Azure uses fixed size VHDs and that resizing them is basically moving around a 512-bytes footer, it does not make sense to me to move around several GBs of data. When looking around, I found WindowsAzureDiskResizer, a tool built in 2013 by Maarten Balliauw that does just this. The tool is efficient since it just rewrites the footer at the end of blob. Although it worked fine for me, I must point out Maarten’s disclaimer:

Big disclaimer: use the provided code on your own risk! I’m not responsible if something breaks! The provided code is as-is without warranty! I have tested this on a couple of data disks without any problems. I’ve tested this on OS disks and this sometimes works, sometimes fails. Be warned.

Though it might seem frightening, keep in mind the whole process described here is non-destructive since we haven’t touched the original VM other than shrinking the partition size, which can easily be undone. We are building a new VM with a new managed disk, so you can always go back to the original one.

That being said, the first version of the tool posted above did not support shrinking, so I forked the repo, updated the dependencies to the latest versions and created a new release for convenience. Again, Maarten’s disclaimer still applies here.

Before using the tool, run the following commands in the same context as the previous step to get the full blob URI including a shared access signature:

$StartTime = Get-Date
$EndTime = $startTime.AddSeconds($sasExpiryDuration)
New-AzureStorageBlobSASToken -Context $destinationContext -Blob $destinationVHDFileName -Container $storageContainerName -Permission rwd -StartTime $StartTime -ExpiryTime $EndTime -FullUri 

The tool accepts two arguments, the size in GB and the full blob URI as returned by the commands above. For example:

WindowsAzureDiskResizer.exe 32 “<SAS>”

If you’re still not comfortable using the tool, you can always go the long way and download the whole virtual disk to a machine with Hyper-V client tools installed, use the edit disk feature or the Resize-VHD cmdlet to shrink the virtual disk and reupload it to Azure. Note that you might have to convert back and forth from the VHD and VHDX formats (Azure only supports VHD at this time).

5. Create a new managed disk from the VHD

No matter the technique used, your smaller VHD should now be uploaded to Azure. To create a new managed disk, run the following commands in the same context as previous steps (adjust variables accordingly):

#Provide the name of the Managed Disk
$diskName = "newManagedDiskName"
#Provide the size of the disks in GB. It should be greater than the VHD file size.
$diskSize = "sizeInGB"
#Provide the storage type for the Managed Disk. PremiumLRS or StandardLRS.
$accountType = "StandardLRS or PremiumLRS"
$vhdUri = "https://$$storageContainerName/$destinationVHDFileName"
$ressourceGroup = Get-AzureRmResourceGroup $resourceGroupName
$diskConfig = New-AzureRmDiskConfig -AccountType $accountType -Location $ressourceGroup.Location -DiskSizeGB $diskSize -SourceUri $vhdUri -CreateOption Import
#Create Managed disk
$disk = New-AzureRmDisk -DiskName $diskName -Disk $diskConfig -ResourceGroupName $resourceGroupName 

6. Create a new VM from the new managed disk

There’s several ways to accomplish this one, you could use PowerShell or an ARM template for example. Whatever option you choose, you need to use “Attach” option for the OS Disk rather than the “FromImage” option. This will create a specialized VM, in other words, the VM is not expected to be generalized (or sysprep’d). Note there’s a little caveat: the computer name will remain empty in the Azure portal, since it’s currently only appears for generalized VMs. Here’s a PowerShell sample you could use, it must be run in the same context as previous steps (adjust variables accordingly):

#Provide the name of an existing virtual network where virtual machine will be created
$virtualNetworkName = "yourVirtualNetworkName"
#Provide the name of the virtual machine
$virtualMachineName = "yourVirtualMachineName"
#Provide the size of the virtual machine
#e.g. Standard_DS3
#Get all the vm sizes in a region using below script:
#e.g. Get-AzureRmVMSize -Location westus
$virtualMachineSize = "Standard_DS1"
#Initialize virtual machine configuration
$VirtualMachine = New-AzureRmVMConfig -VMName $virtualMachineName -VMSize $virtualMachineSize
#Use the Managed Disk Resource Id to attach it to the virtual machine. Please change the OS type to linux if OS disk has linux OS
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -ManagedDiskId $disk.Id -CreateOption Attach -Windows
#Create a public IP for the VM
$publicIp = New-AzureRmPublicIpAddress -Name ($VirtualMachineName.ToLower()+'_ip') -ResourceGroupName $resourceGroupName -Location $ressourceGroup.Location -AllocationMethod Dynamic
#Get the virtual network where virtual machine will be hosted
$vnet = Get-AzureRmVirtualNetwork -Name $virtualNetworkName -ResourceGroupName $resourceGroupName
# Create NIC in the first subnet of the virtual network 
$nic = New-AzureRmNetworkInterface -Name ($VirtualMachineName.ToLower()+'_nic') -ResourceGroupName $resourceGroupName -Location $ressourceGroup.Location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $publicIp.Id
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $nic.Id
#Create the virtual machine with Managed Disk
New-AzureRmVM -VM $VirtualMachine -ResourceGroupName $resourceGroupName -Location $ressourceGroup.Location 

7. Optionally cleanup the old resources

You should now have a fully functional VM with a shrunken managed disk. If not, remember you can always go back to the original VM. Once you are satisfied with your new VM, you could choose to cleanup the old resources like the VM, it’s managed disk, network interface, etc. Obviously, once you’ve deleted the original resources, there’s no going back. You can also delete the temporary VHD used to create the new managed disk. Note that if you do, you won’t be able to reattach the same managed disk to another VM since the source VHD is required when the VM is created.

So those are the steps to shrink a managed disk. Most of these scripts are based on this repo, so check it out for more samples. When creating brand new VMs, we are now seeing images offering smaller sizes by default like the one labelled “[smalldisk] Windows Server 2016 Datacenter”. If such an image does not exist currently, you could build one yourself. Since the VM would be generalized, you would not run into the computer name caveat discussed at step #6.

Hope it helps!

Premier Support for Developers provides strategic technology guidance, critical support coverage, and a range of essential services to help teams optimize development lifecycles and improve software quality.  Contact your Application Development Manager (ADM) or email us to learn more about what we can do for you.


Comments are closed. Login to edit/delete your existing comments