Cloud-init, Hyper-V and a custom image
Today I'm going to go over using Cloud-init with Hyper-V and customizing the base image.
Today I'm going to go over using Cloud-init
with Hyper-V
and customizing the base image.
Overview
I build a lot of VM's and tear them down throughout a general work week, I am tired of spending a bunch of time baby-sitting an installer to enter the same information all the time. I wanted to make this a single script that I can run to create an entire environment.
To accomplish this I needed an image that has Cloud-init setup in it that works with Hyper-V. I chose the Ubuntu cloud image for Azure. Azure runs on Hyper-V so it fit well right out of the box, mostly. I do need to pull out some of the Azure specific customizations. I'll cover that as well.
To customize the image and to remove the Azure components you'll need to be an Administrator on your computer. You will need Windows Subsystem for Linux installed from the Microsoft Store. The reason you need WSL from the store is that we mount the Ubuntu cloud image inside of it so we can customize it. That feature is only in the Store instance of WSL.
To create the virtual machine you will need the Windows Assessment and Deployment Kit with the Deployment Tools
feature. This is used to create the iso
image that contains the Cloud-init configuration.

Assumptions with this post
- You'll be using the
Ubuntu Mantic
distribution. - You have admin rights on your computer
- You have Windows Subsystem for Linux already setup and running with default settings and a distribution with
chroot
. - You're using a directory named
c:\Cloud-init
to store everything. - You have the
Windows Assessment and Deployment Kit
with a minimum, theDeployment Tools
feature installed at the default location ofC:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit
. - You have this repository checked out
Create the base image
Download
First step in creating the base image, download the Azure Cloud-init image from Ubuntu's cloud image site linked here

I'm going to be picking on the latest one, mantic
. The image name for the mantic
version of Ubuntu is mantic-server-cloudimg-amd64-azure.vhd.tar.gz
.
Extract the vhd
Now that you have that downloaded, extract the vhd
file from that archive. You can use WSL to do this, or an application like 7-zip.

Customize the base image
Now that you have the vhd
extracted, we need to customize it.
Here is a link to the create-vm.ps1
script that will convert the vhd
to a dynamically sizing vhdx
, mount the vhdx
in WSL, remove the Azure specific components, and finally chroot
into the mounted vhdx
so you can customize it.
You can execute this from where you checked out the repo in an administrator PowerShell window
./set-cloudinit-ubuntu.ps1 -Source C:\cloud-init\livecd.ubuntu-cpc.azure.vhd -Destination C:\cloud-init\ubuntu-mantric.vhdx
You should be greeted with output that looks very similar to this.
Converting image to a dynamic disk
Mounting in WSL
The disk was successfully mounted as '/mnt/wsl/61447da8-c86a-4526-b900-5048ec59d556'.
Note: The location will be different if you have modified the automount.root setting in /etc/wsl.conf.
To unmount and detach the disk, run 'wsl.exe --unmount \\?\C:\cloud-init\ubuntu-mantric.vhdx'.
Modifying the cloud-init data source
Removing the azure specific configuration
Entering your image environment
Press ctrl+d or type exit when you are done customizing your image
root@edslaptop:/#
You are now in the chroot
environment of your golden image. Customize as you see fit. Once you are happy with your image, press ctrl+d
or type exit
and press enter to exit the chroot
environment.
After you exit the chroot
environment, you should now be greeted with the following
Unmounting from WSL
The operation completed successfully.
Your golden image is now setup and ready to be cloned.
Building your virtual machine
Setup Cloud-init
files
We're going to now setup some basic example Cloud-init files. You can find the example Cloud-init configuration in the example
directory here
Those example files will show how to build a VM with the hostname of example
, a single user with username/password of example
and install curl
and ca-certificates
. It will also enable password based ssh
login, which is disabled by default and upgrade all of the currently installed packages.
Use the Cloud-init configurations and build the VM
Now that you have your Cloud-init configuration build, it's time to build the actual virtual machine. We'll use the create-vm.ps1
script for that. It is very simple to use, here is the minimal usage of the script. It creates a virtual machine named Test
, with a root disk of 30 gigs, using the example
directory, the base image we just created and 4 gigs of memory.
./create-vm.ps1 -VirtualMachineName Test -VirtualDiskSize 30 -CloudInitDirectory ./example -RootDiskPath C:\cloud-init\ubuntu-mantric.vhdx -MemorySize 4
You should now be greeted with an output looking like this.
Copying root disk from C:\cloud-init\ubuntu-mantric.vhdx to C:\ProgramData\Microsoft\Windows\Virtual Hard Disks\Test.vhdx
Resizing virtual disk to 30 gigabytes
Creating cloud init iso at C:\ProgramData\Microsoft\Windows\Virtual Hard Disks\Test-cidata.iso
OSCDIMG 2.56 CD-ROM and DVD-ROM Premastering Utility
Copyright (C) Microsoft, 1993-2012. All rights reserved.
Licensed only for producing Microsoft authorized content.
Scanning source tree
Scanning source tree complete (2 files in 1 directories)
Computing directory information complete
Image file is 57344 bytes
Writing 2 files in 1 directories to C:\ProgramData\Microsoft\Windows\Virtual Hard Disks\Test-cidata.iso
100% complete
Final image file is 57344 bytes
Done.
Creating virtual machine
Disabling dynamic memory
Setting secure boot settings
Adding cidata iso to the virtual machine
Starting virtual machine
Virtual machine creation complete
Check your virtual machine
Open the Hyper-V Manager
application and check your Test
virtual machine, if it's not the basic login
screen then wait a couple of minutes.
Once the login
screen is up, try logging in with the example
user, the password is also example
.
Conclusion
This is the under pinning of how to use Hyper-V, Cloud-init, PowerShell and WSL to customize a base image and actually use it in Hyper-V. Next post will be using PowerShell to easily create a set of Cloud-init files to quickly build a basic Ubuntu virtual machine.
This was a fun project to do. I'm glad I did it, even thought it was a little difficult to figure it all out.
Hopefully you find it useful as well.
Links



