Azure Image Builder or Packer for Azure Virtual Desktop
So you’re in the situation seeking to automate Azure Virtual Desktop (AVD) image creation. You have discovered Packer and Azure Image Builder, but do not know which to use. Hopefully, I will as short as possible try to make sense of the differences, and why you fancy one of them depending on your scenario. Lucky for you it’s no wrong answer, the secret is that you use packer either way 🙂
In the table below I’ve listed some important key capabilities from both services.
To read the entire specification I will also recommend reading the documentation section below that I’ve added in this post.
Concerning the initial table, I’ve additionally explained how you can automate AIB and packer (azure-arm) with Azure DevOps using the marketplace extensions. You do not need to use these, you could also just interact with Azure CLI, etc. My goal is just to show a quick proof of concept with Windows 10 multisession image. Both examples distribute images to SIG.
|Description||Packer (azure-arm)||AIB (azure image builder)|
|Managed by||HashiCorp||“Microsoft” ( with HasiCorp Packer under the hood)|
|Azure RBAC role||Service Principal||Managed Identity|
|Azure Resource Group||Provision resources to the default resource group from packer or existing resource group||Provision resources to the default resource group from packer or existing resource group|
|Distribute||Shared Image GalleryManagedImage,VHD||Shared Image GalleryManagedImage,VHD|
|Communicators (windows) - Packer create certificate only valid 24-hours from invocation time. Uploaded to KeyVault||winrm||winrm|
|Provisioner||Powershell, chef, ansible, puppet , DSC||Powershell|
|Region||All Azure regions||https://learn.microsoft.com/en-us/azure/virtual-machines/image-builder-overview?tabs=azure-powershell#regions|
|Hyper-V Generation (images) https://docs.microsoft.com/en-us/azure/virtual-machines/generation-2||gen1 and gen 2||gen1 and gen 2 (roadmap)|
|Azure DevOps / Infra as Code||Packer task / Build Image task (1.3.4) / Azure CLI and Powershell (1.7.*)||Azure VM Image Builder Task (preview), Azure CLI and Powershell (1.7.*)|
|Security||VNET (default or existing) , NSG (restricted ports) , KeyVault (certificate and secrets)||VNET (default or existing) , NSG (restricted ports), KeyVault (certificate and secrets)|
|Packer.exe||Need to download the latest packer version or specify an older version||Do not have any direct interaction with Packer. Everything goes through the azure image builder service that again uses packer under the hood|
|Configuration syntax||JSON or HCL (preferred from 1.7.0)||JSON|
|Logging||Packer logs are stored in storageaccount||Packer logs are stored in storageaccount|
20.02.2021 the Azure Image builder Service was announced Generally available, but Microsoft suddenly apologized to the publication and pulled the GA status. I do not think it far away, and we could probably still expect it to hit GA Q2 or Q3 in 2021.
07.06.2021 Azure Image builder Service was announced Generally available.
Image Creation Deployment High Level Design
If we look into the high-level design of how we can create and deploy WVD, it could look similar to this process. The building blocks for WVD image creation and image deployment will involve many phases before we have the end product. With help from packer, AIB ,SIG Azure DevOps we have tools to support automation of this process.
- use marketplace SKU (add this to our code)
- choose the latest offer, windows version supported by your organization (add this to code)
- build pipeline with AIB or Packer with info from 1 & 2
- provisioner – install windows features and custom applications from azure storage/azure files /package manager
- distribute the shared image gallery across regions
- trigger ARM or TF deployment with the latest release of the ID from SIG.
- start windows customization extensions phase
- domain join extension
- host pool join dsc extension
- custom PowerShell extension (example WVD optimization script )
- VM added to host pool ready for testing or production.
Getting started with Azure Image builder with Azure DevOps
Following that the AIB is not GA, we are required to register the preview service. Follow this guide from Microsoft to VirtualMachineTemplatePreview for the preview. https://docs.microsoft.com/en-us/azure/virtual-machines/windows/image-builder-powershell#register-features . This step is not required when GA!
I’ve already created Managed Identity with permissions and added permissions to allow SIG with the guide below.
When all prerequisites are in place we can start adding the Azure VM Image Builder Test (Preview) in Azure DevOps. You can also use azure cli or powershell task´s.
Create Azure DevOps Project
The first task is to create a new project in Azure DevOps dev.azure.com. I will do it manually, but you can do this with Terraform if you need to automate this multiple times: https://techcommunity.microsoft.com/t5/itops-talk-blog/how-to-use-terraform-to-create-azure-devops-projects/ba-p/1555471. We can use the same project for both pipelines.
Add the marketplace task and install the Marketplace extension for AIB preview
You can grab the Marketplace extension for AIB (preview) from https://marketplace.visualstudio.com/items?itemName=AzureImageBuilder.devOps-task-for-azure-image-builder
Add you github service connection
I’m using Github as source control.
Create your pipeline for Azure Image Builder
Choose pipelines – Classic editor and connect your github account and empty job
I’m using the classic editor to create the pipeline.
go back to the release pipeline and add your Azure Image Builder tas
Let’s look into the required fields for the extension.
In the first step of the template, we need to Add your azure subscription, resource, and managed identity resource id.
In the Customize step set your custom script. It will copy the scirpt from my github workingdirectory and copy it over to the directory on the Virtual Machine. The default location for Inline customization script will runt from the VM in “C:\BuildArticacts” in this step you can install apps or do any custom configuration that you need. I
It’s not any requirement to specify Sysprep. AIB will do the Sysprep for us!
NB! I’ve specified only WestEurope as SIG region, If you choose more than 1, your build will fail because it exceeded the 1-hour limit.
(One free job that can run for up to 60 minutes each time). It does help much to choose a bigger VM because SIG is the slowest part. Even though the job fails the SIG will succeed after checking the Azure portal.
You can buy and read more about parallel jobs :
Running the build will output this on successful task.
You can also check Shared Image Gallery to verify your newly added image from the AIB Pipeline.
The final YAML pipeline will look like these. You can use this to standardize your azure pipeline deployments for CI /CD
Getting started with Packer azure-arm with Azure DevOps
Many other blogs use the Build machine image task to build an immutable image. My problem with the task is that it uses packer version 1.3.4, which is old. I want to use the latest packer version because I want to use the Shared Image Gallery with packer. So to solve this we use Azure CLI or Powershell that use our packer JSON or HCL file, which will be used by the pipeline as input. With Azure CLI or Powershell you should from my experiance always get the latest packer version installed. I will use the JSON template since I’ve not upgraded my templates to HCL. (upgrading to HCL will be another blog).
For authentication, I will use a service principle. NB! If you want to use a Managed Identity, you need to create an Azure Virtual Machine that has Managed Identity enabled, and then use this VM to run your build.
The first step is to add Variable Group. All variables that Packer needs are stored here.
In My KeyVault I’ve added all details from my Service Principal account that Packer will use for (azure-arm).
I’ve added all secrets to Key Vault “wvd-kv” and all other variables to “wvd-packer-vars” as shown in the picture below.
To link the Variable group to the DevOps project choose variables group add key vault.
Remember to link secrets as key vault variables.
Create your Azure DevOps Pipeline for Packer
Let’s configure the Pipeline. I’ve added 2 tasks. Packer validate and Packer build
choose pipelines – Classic editor and connect your github account and empty job as we did in the steps above earlier.
In the Inline Script I will add the validate shell script. To verify that there are no obvious parameters missing.
In the Inline Script I will add the build shell script. I’m adding the variables with export and generating timestamp for one of the variables (image_version) to set the semantic version that’s required by SIG.
The Packer template will in summary use variables we have defined. Create Image with windows 10, sysprep VM add it to SIG.
To fully understand user variables go to https://www.packer.io/docs/templates/legacy_json_templates/user-variables
Link Variable Groups to the Packer pipeline. This is important step. Without adding the Variables the build will fail!
When running the build we can see that it’s started the azure-arm packer Build stage.
In Shared Image Gallery we can find the new image created by the Packer build template.
The YAML pipeline for Packer for setups looks like this.
You can use this to standardize your azure pipeline deployments for CI /CD
if you see this error with Packer below. You have most likely not configured or linked the variable group or added the wrong variable for Client Secret, ClientID etc .
azure-arm: Running builder
azure-arm: Getting tokens using Managed Identity for Azure
if you see this error with AIB below. You have not given correct access to your managed identity for either shared image gallery or storage account.
[error]Error: put template call failed for template t_undefinedundefined_1622201565931 with error: Not authorized to access the resource: /subscriptions.
If your packer stops under the deployment all logs are stored in the storage account. Use CMTrace.exe to debug the log file.
This post was not intended to create a battle between the two ways of using packer. As you can see it all gets down to current preferences.
AIB could maybe be the solution if you seek a lighter way to rapidly adapt and develop image creation without understanding all the packer details. This could also benefit the DevOps teams because I think simplicity is relevant to the DevOps team that needs to maintain and support further image development for the customer. To be subjective the only thing that could hold me back from using AIB, is the need for GA or Region Availability. Most WVD deployments I’m involved in requires other regions. With Managed Identity as default, this is my most preferred way to scope access control, so I like this option.
The first time I used packer was related automation images to my home lab with VMware ESXi. Packer has multiple Builders for all the big players – https://www.packer.io/docs/builders. Using the Azure provider is generally different than using the VMware provider. But If you are familiar with packer, the adaption to the Builder for Azure (azure-arm) is pretty seamless. However, as listed in the table above there are also many motives why you may want to go the packer route. With the table above you can see that Packer provides the best granular and flexible control over the azure environment, you are managing. You can control “everything”. But looking back to AIB we do not need to think about specifying the packer version. I’ve encountered different errors if I’ve used an older version of packer. Some of my experience with Packer is that if you forget to validate your template or have some wrong variables this can set you back some hours of troubleshooting.
That’s it for this time! Good luck with automating your AVD images in whatever way you prefer 🙂 I had a talk about this blog at AVDTechfest 2021 https://youtu.be/G2g8CVVzZP4?t=15251 and powerpoint deck https://github.com/alventech/talks/tree/main/2021/avdtechfest