Packer is a great tool to build images. This blog is about using YAML to build your Packer Azure DevOps Pipeline. When using YAML, it is very easy to replicate your pipeline to other Azure DevOps organizations. So, what is the architecture about?
Firstly, let’s start with this high level design of a packer build:
The packer build runs basically in 3 “main steps”.
1. The windows based agent which is connected to your Azure DevOps environment starts the build. Packer is downloaded alongside the templates from the DevOps GIT repository.
2. Packer runs on the “Windows Based Agent” and start to create a seperate resource group where the VM is build. Firstly, the VM is created. After that, the provisioning process starts. Windows Updates and applications are installed.
3. The last step is that the VM is sysprepped and generalized to output a managed image in a seperate resourcegroup. After that, the resource group with the VM and the resources needed is deleted.
In addition, a forth step could be that the managed image is uploaded to a Azure Compute Gallery. I will write a part 2 to this blog which features adding the shared image gallery to this build.
You need to have your Azure DevOps organization and Azure tenant setup. I have written a blog on how to do so. This is the link.
After that, you are ready to start this blog!
Add Packer to Azure DevOps
Firstly, we need to add Packer to Azure DevOps in order to use this feature.
Log on to Azure DevOps.
Next, go to Organization settings:
After that, go to extensions:
Browse the marketplace and search for Packer:
Click on “Get it free”:
Select your organization and click install:
Packer is now available in your organization:
Create the Key Vault
Firstly, we need to make sure that the “Service Principal Application ID” and the “Service Principal Secret” are available in your Azure Key Vault.
If you don’t have an Azure Key Vault, we first need to create one.
Go to the Azure Portal and click on create a resource:
After that, search for “Key vault” and create one:
Make sure your Service Principal may access the Key vault:
I am allowing all networks. If you limit this option, make sure your Azure DevOps environment and Agent can reach the keyvault.
After this, go to review and create.
Lastly, create the Key Vault.
Go to your keyvault and go to “Secrets”:
Add your Service Principal App ID and Service Principal Secret:
Go back to Azure DevOps. Go to Pipelines and to Library:
Create a new variable group:
Call it Azure Key Vault and add the variables from the newly created Azure Key Vault:
Now you can use the variables in your pipelines.
Create the Packer Pipeline
Firstly, we need another variable group. Go back pipelines and to library:
Create a new variable group:
Add these variables to the group:
ARM_Subscription_ID –> the ID of the subscription that you want to deploy in. (The service connection must also be mapped to this subscription.
az_tenant_id –> This is ID for your Microsoft 365 Tenant
Location –> This is the location of the Resource Group for the Managed Image.
resourcegroupname –> This is the name of the Resource Group for the Managed Image.
ServiceConnectionName –> This is the name of the Service Connection used.
After that, we add the packer files to Azure DevOps. I put these files in Github account. You can find them here:
1. Windows 10 Packer template file.
2. Windows 10 Packer variable file.
3. Windows 10 Packer YAML file.
4. ARM template for creating a resource group.
Put these file in your GIT repo in a folder called “Packer”. Furthemore, if you put the files here. you don’t have to change the paths in the YAML file later.
In addition, I have also displayed the YAML file here. I need to explain a few variables.
trigger: none pool: name: 'AGENT POOL NAME' variables: - group: 'PackerVariables' - group: 'YOUR VARIABLE GROUP (KEYVAULT)' stages: - stage: CreateResourceGroup jobs: - job: CreateResourceGroup steps: - task: AzureResourceManagerTemplateDeployment@3 inputs: deploymentScope: 'Resource Group' azureResourceManagerConnection: '$(ServiceConnectionName)' subscriptionId: '$(ARM_Subscription_ID)' action: 'Create Or Update Resource Group' resourceGroupName: '$(resourcegroupname)' location: '$(Location)' templateLocation: 'Linked artifact' csmFile: 'Packer/EmptyResourceGroup.json' deploymentMode: 'Incremental' - stage: RunPacker jobs: - job: CreateImage steps: - task: riezebosch.Packer.PackerTool.PackerTool@0 displayName: 'Use Packer Latest' - task: riezebosch.Packer.Packer.Packer@1 displayName: 'Packer version' inputs: azureSubscription: '$(ServiceConnectionName)' templatePath: 'Packer/Windows10AVDImage.pkr.hcl' command: version - task: riezebosch.Packer.Packer.Packer@1 displayName: 'Packer init' inputs: azureSubscription: '$(ServiceConnectionName)' templatePath: 'Packer/Windows10AVDImage.pkr.hcl' command: init - task: riezebosch.Packer.Packer.Packer@1 displayName: 'Packer validate' inputs: azureSubscription: '$(ServiceConnectionName)' templatePath: 'Packer/Windows10AVDImage.pkr.hcl' command: validate variables-file: 'Packer/Windows10AVDVariables.pkr.hcl' - task: riezebosch.Packer.Packer.Packer@1 displayName: 'Packer build' inputs: azureSubscription: '$(ServiceConnectionName)' templatePath: 'Packer/Windows10AVDImage.pkr.hcl' variables-file: 'Packer/Windows10AVDVariables.pkr.hcl'
Firstly, you need to change these variables in the YAML file:
‘AGENT POOL NAME’ –> Name of the pool of agents created in the preparation part.
Don’t change the name of the ‘PackerVariables’ group.
‘YOUR VARIABLE GROUP (KEYVAULT)’ –> If you followed this blog, this ‘AzureKeyVault’. If you did not, please enter your own Key Vault name.
Furthermore, if you did not put the files in the folder “Packer” please change these variables:
For the ResourceGroup creation:
And foreach Packer task:
After that, we edit the Packer Variables files. The file looks like this:
Make sure you edit the following variables:
client_id –> Insert he variable from the AzureKeyVault variable group.
client_secret –> Insert he variable from the AzureKeyVault variable group.
virtual_network_name –> Name of your Virtual Network in Azure.
virtual_network_resource_group_name –> Name of your Virtual Network ResourceGroup Name.
virtual_network_subnet_name –> Name of the subnet in Azure.
In addition, by default the private_virtual_network_with_public_ip is set to false. Make sure that your agent can make a WinRM connection to the private IP address of the VM that is created by Packer. If you are not sure, set this to “true”.
Lastly, it is finally time to create the Packer Pipeline itself. Go Pipelines and select Pipelines:
After that, create a new pipeline:
In addition, if you don’t have any pipeline it will ask you to create your first pipeline.
Lastly, click on save:
And that’s how your create a Packer YAML pipeline in Azure Devops!
Packer YAML pipeline example run
Click on Run Pipeline:
Firstly, the resource group task runs:
After that, the packer build starts:
WinRM connects, downloads and install Windows Updates:
Reboot & Sysprep:
Lastly, the managed image: