Custom Image Templates part 3
Create Custom Image Templates using Bicep and Azure CLI
In the previous parts of this blog you have got some more information what an Image Template is and can be configured to have more control over your base image. In part 2, I have also shown you a deployment method, and why I want to use Infrastructure as Code as my main deployment method. I concluded the blog with an example of deploying the Bicep files using az deployment sub
.
But there are other ways to deploy these bicep files, in this blog i will show you another example. I will also start building an image, using az image builder in combination with the deployed Image Template.
Deploy bicep files using a deployment script
To have more control over your deployment, you can use a deployment script. Using a deployment script offers many benefits, such as error handling, custom logic, managing dependencies, ensuring consistency, and repeatability. Sometimes, deployment requires more than just deploying the Bicep code. A deployment script can help in such scenarios. For example, if you need to perform clean-up tasks after the deployment, the script can handle this for you. Deployment scripts are also integrated with CI/CD pipelines, ensuring a consistent deployment method. Additionally, error handling is a significant advantage when you use a deployment script.
So let's dive in to a deployment script and deploy the Image Template with an deployment script.
1param(
2 [Parameter(Mandatory = $true)][string] $subscriptionID = "",
3 [Parameter(Mandatory = $true)][ValidateSet("northeurope", "westeurope")][string] $location = "",
4 [ValidateSet("avd")][string][Parameter(Mandatory = $true, ParameterSetName = 'Default')] $productType = "",
5 [Parameter(Mandatory = $true, Position = 3)] [validateSet("prod", "acc", "dev", "test")] [string] $environmentType = "",
6 [switch] $deploy
7)
8
9# Ensure parameters are captured
10Write-Host "Subscription ID: $subscriptionID"
11Write-Host "Location: $location"
12Write-Host "Product Type: $productType"
13Write-Host "Environment Type: $environmentType"
14
15$deploymentID = (New-Guid).Guid
16
17<# Set Variables #>
18az account set --subscription $subscriptionID --output none
19if (!$?) {
20 Write-Host "Something went wrong while setting the correct subscription. Please check and try again." -ForegroundColor Red
21}
22
23
24$updatedBy = (az account show | ConvertFrom-Json).user.name
25$location = $location.ToLower() -replace " ", ""
26
27$LocationShortCodeMap = @{
28 "westeurope" = "weu";
29 "northeurope" = "neu";
30}
31
32$locationShortCode = $LocationShortCodeMap.$location
33
34if ($deploy) {
35 Write-Host "Running a Bicep deployment with ID: '$deploymentID' for Environment: '$environmentType' with a 'WhatIf' check." -ForegroundColor Green
36 az deployment sub create `
37 --name $deploymentID `
38 --location $location `
39 --template-file ./imagetemplate.bicep `
40 --parameters ./imagetemplate.bicepparam `
41 --parameters updatedBy=$updatedBy location=$location locationShortCode=$LocationShortCode productType=$productType environmentType=$environmentType `
42 --confirm-with-what-if `
43}
In this script, you will have some mandatory parameters that match those in the Bicep files. For these parameters, we have also set the validateSet
, so you need to provide values that comply with your naming convention and the region where you want to set up the resources.
If you want to add another region as compliant, you need to include it in the validateSet
. As you can see, this script is designed to be modified to fit the standards you prefer.
For auditing purposes, there is an automated updatedBy
field included in the deployment. This is especially useful if you want to track who executed the deployment.
At the end of the script, there is the az deployment sub create
command, which performs the same action as described in my blog (part 2) but with some additional features. The --confirm-with-what-if
flag is particularly useful for running deployments in an existing environment, as it allows you to see what changes will be made and provides an extra confirmation step by asking if you want to proceed with the deployment.
How to Run the Script
Running the script is straightforward. Open a terminal, navigate to the directory where you have stored the deploy-now-imagetemplate.ps1
file. I recommend storing the other two files, imagetemplate.bicep
and imagetemplate.bicepparam
, in the same directory, as the script automatically looks for them there.
Before running the command, log in to the environment where you want to deploy by using az login
in your terminal. Authenticate and ensure you are pointing to the correct subscription. Then, use the following commands to deploy the script.
If you want to fill the rest of the information in the terminal you can use:
1.\deploy-now-imagetemplate.ps1 -deploy
If you want to do it in one command fill in the details like the example listed below, keep in mind that you need to fill in your own values.
1.\deploy-now-imagetemplate.ps1 -subscriptionID "" -location "" -productType "" -environmentType "" -deploy
If you have run one of these commands you will deploy your resources needed for creating the Image Template
Deploying the Image Template
We have now deployed resources that are needed to build the image. How cool would it be to do it with an command instead of using the Azure portal. Because there is no Powershell command for we will use the Azure CLI, so let's begin:
First, Login using az login and select your subscription.
1az login
We know that we have stored an image template in the resource group because we have just created it, but let's check:
1az image builder list --resource-group "rg-avd-prod-weu" --query "[].name" --output json | ConvertFrom-Json
This is the outcome:So let's store it in a variable, so we can call it later, and after that a double-check, when calling the variable:
1$imagetemplate = az image builder list --resource-group "rg-avd-prod-weu" --query "[].name" --output json | ConvertFrom-Json
2
3$imagetemplate
This is the outcome:
As you can see we have the correct output, you can check this of course in your resources because the same name will be visible in the resource group. When you have multiple Image Templates you can make the query a little smarter, as an example you can sort or check on creation time. If you want, you can always store the resource group in a variable if needed, this is especially handy when we are going to work with pipeline deployments in the later blogs.
Let's start the build process:
1az image builder run -n "$imagetemplate" -g "rg-avd-prod-weu" --no-wait
If you go to the Azure portal you can check the status in the Image Template, if everything is going according plan the status will be:
During the creation proces an extra Resource Group with an auto generated name will appear, because we didn't fill in an Resource Group for the creation it will create one. This Resource Group will spin-up the necessary resources and will be clean-up after the creation process. The Resource Group must be manually cleaned up. But in the next blog when i explain how to do this with *Azure DevOps Pipelines we will create automation to clean this up for you.
When you don't want the autocreate this group you can specify a empty Resource Group in the bicep file using the stagingResourceGroup value, keep in mind that this group needs to be empty, if not, it will still create an auto-generated resource group. The Resource Group also needs RBAC permissions for the Managed Identity, this can be the contributor role.
The build proces itself can take a little while but it also depends on the image and the scripts which are added. There are commands to see the progress you can find more information about the az image builder on this page
When the deployment is finished, you can go the Azure portal, where you will see a new version under the image definition.
Wrapping up
In this part of the series, we explored how to streamline the deployment of custom image templates using deployment scripts and the Azure CLI. By leveraging automation, we gained more control over the deployment process, reducing the risk of errors and ensuring consistent results. The deployment script simplifies the setup process, integrates seamlessly with CI/CD pipelines, and allows for efficient resource management.
Additionally, we demonstrated how to build an image with the deployed image template using az image builder
. This hands-off, automated approach reduces manual intervention and accelerates the deployment process.
Stay tuned for part 4, where we will delve into using Azure DevOps pipelines to further automate image deployments and set up additional resources for Azure Virtual Desktop. With this end-to-end approach, you’ll be able to create, deploy, and manage custom images effortlessly.