At a customer I am helping to set up a pipeline to spin up a complete new environment every night. The environment consists of multiple machines. 2 of the machines are preconfigured and cannot be automated (not now at least) with ARM and DSC to create everything from code (which is of course the best alternative. besides containers…and PaaS and.. SQUIRL!) .
To overcome this, we created a VHD that has everything on it and stored this VHD in an Azure Storage Account as a template. Every time we spin up a new environment with ARM, we copy the VHD to a new storage account and use ARM to attach the existing VHD to the newly created machine. We do this at least 1 time per day, but sometimes more.
It works like a charm, but the VHD, that was created by Azure, is 130 Gb. Not really a problem, but starting up our ARM template, starts with copying 2 of these files to a new Storage account, eating the first 15 minutes of our deployment (yes, even with AzCopy). Worst of it all is that the Active Directory server is actually using 12 Gb and the other machine is using 23 Gb. So we copy about 240 Gb for nothing. My goal. Shrink the files in the templates folder so that the copy will only take about 5 minutes (or less). That was not as easy as it may seem.
Some things you should know
Before I walk you through the process of actually doing it, there are a few things you should know about Azure VHD
- Windows machines that are created in Azure automatically get a VHD of 130 Gb
- VHD’s in Azure should be fixed size. If they are dynamically expanding, the resource will not come up automatically
- VHD files cannot be shrunk, only VHDX files
Steps to follow
In order to make a VHD smaller follow these steps
Shrink the size of the machine
Azure uses Fixed disks, so windows thinks there is a 130Gb disk attached to the machine. Login to the machine and go to Disk Management. Click the Disk and choose Shrink. You end up with many Gb of Unallocated space. Make sure you do not shrink the disk completely. Keep some extra space for logs etc.
Detailed steps to do this are described here
Create a VHDX and shrink it
Now you need to create a VHDX of the disk so that the actual size can be made smaller as well. Because the file is still 130 Gb and that stays the same. You can download the 130Gb and convert it to VHDX, you can also use Disk2VHD from SysInternals to create a VHDX with only the contents.
You can temporarily format the unallocated space to store the VHDX. If you do that keep in mind that your new disk still thinks there is an allocated disk.
Shrink the VHDX
For this you need the Hyper-V tools or the Powershell Cmdlets. Make sure you get the VHDX file somewhere, where these tools are installed. Unfortunately, not on the Azure machine, because the Hyper-V tools do not work there. For example, use Azure Storage Explorer to upload the file to a storage account in Azure
Download the file for your storage account and either user the Hyper-V Edit Disk tool or the Powershell CmdLet
Resize-VHD –Path .\TESTMACHINE.vhdx –ToMinimumSize
When you put the VHDX on the same machine on the disk that was first unallocated and now not anymore, start up the VHDX in Hyper-V first to unallocate the disk again. Otherwise the disk will not be shrunk.
Convert VHDX to VHD as Fixed size Disk and upload to Azure
Now we have the VHDX, we need to create a fixed size VHD from it. Use the powershell cmdlet
Convert-VHD -Path .\TESTMACHINE.vhdx -DestinationPath .\TESTMACHINE.vhd
Test your changes
Now create a copy of the VHD file (to keep the original safe) and use this Github Azure template to create an Azure Virtual Machine based on this VHD. If this works you’re done!
It takes some time and some steps, but in the end it just works fine and save us (at least me) a lot of waiting time during deployment.