Using Differencing VHDs with Hyper-V for Rapid Deployment in Test Environment

Watching some instructional videos yesterday I came across a useful trick using a feature I mentioned in a past post, VHDs on Bare Metal, that now seems so obvious that I must have thought about it and forgot. Using a differential disk to quickly deploy multiple similar machines in a test environment.

In the past I’ve sysprepped and used VMware’s ESXi and vSphere to create templates and clone VMs to quickly deploy new ones. However when I setup my home lab I chose to use Hyper-V to simplify some issues with the mixed hardware I would be dealing with. Hyper-V’s method of cloning isn’t as streamlined as VMware’s and I haven’t really been fond of it. You have to export your VM and then import it, and that’s too bothersome for me.

This is where differencing disks come to the rescue. First you create a VM like you normally would, install whatever operating system you choose, make any configuration changes you desire, add any software you wish, whatever you would normally have to do (besides identifying information and static IPs), then you prepare it for cloning. Which is Sysprep on Windows, or OEM mode on Ubuntu, and whatever equivalents for other operating systems.

This part is optional but I like this idea because of how important this initial VHD you’ve created is. Delete the VM you just created but don’t delete the VHD file. Next mark the VHD file as Read-Only. This is to prevent you from accidentally starting the wrong VM, accidentally booting from this VHD file, or modifying the contents of the VHD file. Changes cannot be made to the parent VHD file if you have a differencing disk pointed at it. The parent file isn’t aware of this relationship and as such wont stop you from using it, however if you do use/modify it you’ll break the relationship between the differencing disk(s) you’ve created that use this VHD as their parent. This is why it’s important to ensure you don’t make any changes.

PS C:\> Set-ItemProperty "D:\VirtualDisks\Sysprepped\base-ws2016-core.vhdx" -Name IsReadOnly -Value $true

Now that the parent is created we can create the differencing disks. You can use the Hyper-V Manager to do this if you prefer the GUI, I prefer to use PowerShell. Especially if I’m creating many at once, as I can just use the command history and change a few switches/variables nice and quickly. I should note, that if you do wish to use PowerShell you’ll need to ensure you have the Hyper-V Module for Windows PowerShell installed to use the following commands.

PS C:\> New-VHD -ParentPath: "D:\VirtualDisks\Sysprepped\base-ws2016-core.vhdx" -Path "D:\VirtualDisks\Diff-Test-01.vhdx" -Differencing

PS C:\> New-VHD -ParentPath: "D:\VirtualDisks\Sysprepped\base-ws2016-core.vhdx" -Path "D:\VirtualDisks\Diff-Test-02.vhdx" -Differencing

PS C:\> New-VHD -ParentPath: "D:\VirtualDisks\Sysprepped\base-ws2016-core.vhdx" -Path "D:\VirtualDisks\Diff-Test-03.vhdx" -Differencing

Just like that I have three copies of that Windows Server 2016 Core install. Now to create the VMs that will use them.

PS C:\> New-VM -Name "Diff-Test-01" -Generation 2 -MemoryStartupBytes 1GB -VHDPath "D:\VirtualDisks\Diff-Test-01.vhdx" -SwitchName "External Network"

PS C:\> New-VM -Name "Diff-Test-02" -Generation 2 -MemoryStartupBytes 2GB -VHDPath "D:\VirtualDisks\Diff-Test-02.vhdx" -SwitchName "External Network"

PS C:\> New-VM -Name "Diff-Test-03" -Generation 2 -MemoryStartupBytes 4GB -VHDPath "D:\VirtualDisks\Diff-Test-03.vhdx" -SwitchName "External Network"

Bam, three Windows Server 2016 Core VMs ready to go, easy as pie. Now we can start those up like so:

PS C:\> Start-VM Diff-Test-*

Voilà! All three VMs have been started. Wasn’t that easy?

There are of course some caveats, like potentially some performance issues, as well as storage issues down the road. The longer the machines live the further their state will drift from the original base installation you created, as you install roles, features, applications, or system updates. This will defeat some of the purpose of using this feature in the first place, the reduction in used storage space, and is another reason you likely shouldn’t use it in production. So just like images you create for desktop/laptop deployment you’ll want to update them over time to include changes and system updates, and maybe keep different versions around as well.

If you’re feeling edgy, you can pull an Inception and go deeper, and use differential disks on differential disk on differential disks on differential disks. Using however many layers you wish, to keep varying different machine states around in much the same way Checkpoints/Snapshots would work. Or you can just copy the VHD file, make your changes to that file, and stay a little bit more sane.