In previous steps you setup all required connections and credentials, so that you can build virtual machine image of your build agent.
Microsoft hosted agents images are built automatically and microsoft open-sourced the configuration scripts in GitHub repository. This is very good starting point and you can use the same scripts. Optionally you can modify those to change some software installation or configuration.
Microsoft uses Packer to build agent image. Packer is nice tool for building virtual machine images. It works with Azure, AWS, Google Cloud, Hyper-V, VMware, and many more. Basically it does following steps:
- Starts a new virtual machine.
- Executes steps specified in JSON template.
- Stops the virtual machine and saves it to an image.
At the GitHub repo there are several images. This article focuses on Hosted 2017 that is defined in template file images/win/vs2017-Server2016-Azure.json. At first fork the whole repository at GitHub, where you will manage your changes. This way, when Microsoft releases a new version of the template, you can easily merge it into your repository. Microsoft stores releases in branches releases/YYMM. Find the latest release and checkout your own branch. Now you can do changes in the template. First section in the template JSON defines, where the image is created. It is created in Microsoft Azure in specified subscription and resource group.
To make installation more secure remove the hardcoded password. Find line
"install_password": null
and replace it with line
"install_password": "{{env `INSTALL_PASSWORD`}}"
Second section defines set of PowerShell scripts, which are executed and install and verify software on the build agent. Configuration of full build agent takes more than 8 hours. Therefore I recommend that you remove installation steps, which you don't need.
Example of modified Packer configuration can be found in repository duracellko/azure-pipelines-image-generation.
When you commit all the changes and push the branch to GitHub, you are ready to create Azure Pipeline to build the image. The build is very simple, it just runs Packer to build the image.
- In Azure DevOps select Pipelines from menu and then Builds.
- Click New build pipeline.
- Click Use the visual designer.
- Select GitHub as source and select your forked repository.
- Click Continue.
- Click on "Start with an Empty job".
- Set Name to Build Agent Image.
- Set Agent pool to Default. This assumes that there is already an agent image in your Default pool. You can use also hosted agent pool, but you have to purchase at least 1 parallel pipeline. Otherwise the build gets cancelled after 30 minutes.
- Select Get sources section.
- Set Clean to "true" and Clean options to "All build directories".
- Select Variables section.
- Open Variable groups section.
- Click Link variable group.
- Select Azure subscription group and click Link.
- Click Link variable group.
- Select Azure resources group and click Link.
- Open Options section.
- Set Build job timeout in minutes to 1440. That is 24 hours.
- Open Tasks section and select Agent job.
- Set Display name to "Build image".
- Click Add task and select Download Build Artifacts. Then set following values:
- Display Name: Download Build Scripts
- Specific build
- Project: Current Azure DevOps project
- Build pipeline: Build scripts
- Build version to download: Latest from specific branch and specified Build Tags
- Branch name: refs/heads/master
- Build Tags: empty
- Specific artifact
- Artifact name: build
- Matching pattern: **
- Destination directory:
$(Build.BinariesDirectory)\scripts
- Click Add task and select Copy Files. Then set following values:
- Display name: Copy Files - Build Scripts
- Source Folder:
$(Build.BinariesDirectory)\scripts\build
- Contents: **
- Target Folder:
$(System.DefaultWorkingDirectory)\scripts
- Clean Target Folder: checked
- Overwrite: checked
- Click Add task and select PowerShell. Then set following values:
- Display name: PowerShell Script
- File Path
- Script Folder:
scripts/BuildImage.ps1
- Arguments:
-SPClientId "$(Azure.ClientId)" -SPClientSecret "$(Azure.ClientSecret)" -SubscriptionId "$(Azure.SubscriptionId)" -TenantId "$(Azure.TenantId)" -Location "$(Azure.Location)" -RGName "$(Azure.ResourceGroup)" -StorageAccountName "$(Azure.StorageAccountName)"
- ErrorActionPreference: Stop
- Click Add task and select Copy Files. Then set following values:
- Display name: Copy Files - VHD URI
- Source Folder:
$(Build.BinariesDirectory)
- Contents:
*.txt *.md
- Target Folder:
$(Build.StagingDirectory)\image
- Clean Target Folder: unchecked
- Overwrite: unchecked
- Click Add task and select Publish Build Artifacts. Then set following values:
- Display Name: Publish Artifact: image
- Path to publish:
$(Build.StagingDirectory)\image
- Artifact name: image
- Artifact publish location: Azure Pipelines/TFS
- Save the pipeline.
- Queue the build. Do not forget to specify branch that you want to build.
After several hours a disk image (VHD file) should be created and stored in the Azure Storage that you created in the first task. Additionally build artifacts contain markdown file with all installed software.
Next step: Deploy build agent