Deployment Pipelines For Versioned Azure Resource Manager Template Deployments
Editor's note: The following post was written by Visual Studio and Development Technologies MVP Peter Groenewegen *as part of our Technical Tuesday series. James Chambers of the Technical Committee served as the Technical Reviewer of this piece. *
Azure Resource Manager templates offer you a declarative way of provisioning resources in the Azure cloud. Resource Manager templates define how resources should be provisioned. When provisioning resources on Azure with Azure Resource Manager, you want to be in control of which resources are deployed, and you want to control their life span. To achieve this control, you need to standardize the templates and deploy then in a repeatable way. This can be done by managing your resource creation as Infrastructure as Code.
The characteristics of Infrastructure as Code are:
- Declarative
- Single source of truth
- Increase repeatability and testability
- Decrease provisioning time
- Rely less on availability of persons to perform tasks
- Use proven software development practices for deploying infrastructure
- Idempotent provisioning and configuration.
In this article, I will explain how to leverage a deployment pipeline and create Azure infrastructure with versioned Azure Resource Manager templates (ARM templates). For the deployments in this article, the VSTS Build and Release pipelines will be used. The code or ARM templates will be managed from a Git repository. Code in the Git repository can use similar practices as any other development project. By updating your code or templates, you can deploy, upgrade or remove your infrastructure at any time. The Azure portal will no longer be used to deploy your infrastructure because all ARM templates are deployed by deployments pipelines. This will give you full traceability and control over what is deployed into your Azure environment.
Deployment pipelines for deploying versioned ARM templates
If you have a large number of infrastructure resources, it is good to know what the exact footprint is. If you know this, you can easily redeploy and create test environments without the constant question: to what extent is this infrastructure the same as production? In order to obtain adequate control over your infrastructure, you can apply versioning to the deployments and their content. In this case, ARM templates in combination with VSTS can help you. When applying Infrastructure as Code this way, you can test an actual infrastructure deployment and develop new templates at the same time. To do this you need two deployment pipelines:
- Deployment of the reusable ARM templates (see the article on Best Practices Azure Resource Manager templates)
- Pipeline for deploying the resource base on the reusable ARM templates.
The templates used in the second pipeline are deployed in the first pipeline. These are called linked ARM templates. A linked ARM template allows you to decompose the code that deploys your resources. The decomposed templates provide you with the benefit of testing, reusing and readability. You can link to a single linked template or to a composed one that deploys many resources like a VM, or a complete set of PAAS resources.
Deployment pipeline for reusable linked ARM templates
The goal of this pipeline is to deploy a set of tested linked templates (a version) to a storage account from where they can be used. Each time you perform an update to the templates (pull request), a deployment pipeline is triggered (continuous integration), and once all tests are successful, a new version is deployed and ready to use. The new deployments exist side by side with the earlier deployment. In this way the actual resource deployments can use a specific version. The following figure provides an overview of the pipeline:
Build
The deployment starts with a pull request to the master branch of the Git repository. Then a new build is triggered. In this build pipeline, the sources are copied to a build artifact to be used in a release. In addition, a build number is generated that can be used as version number of the released templates.
Release
The release has several release steps to ensure that the ARM templates are tested before they are published. Templates are tested by deploying the resources. In the sample, all steps are an automatic process. When the tests succeed, the release continues with the deployment of the templates to the storage account where they can be used for the real infrastructure deployments.
Deploy test
The first step is to deploy to a test location on the storage account. This test location will be used to test the ARM templates by doing test deployments. When you deploy the templates, this can also help you in debugging errors by running a test deployment from your local machine where you can point to the test storage container to run the templates from there. The only task in the environment is to do an Azure Blob File Copy. All the linked templates (the artifacts) are deployed to the Azure storage account (configure the storage account in the Azure Portal when you setup your deployment pipeline).
Test ARM templates
In the second step, the ARM templates can be tested. First you get a SAS token to access the storage account. The next step consists of deploying the ARM templates. This runs a test ARM template that covers the parameters. If the deployment fails, the pipeline is stopped (asserted). The last step consists of removing the resource group where you have deployed your test resources. If all steps succeed, the templates are approved for release.
You can perform these regression tests to verify the changes to your templates do not break the common usages. Add for each configuration combination that you want to test a separate step. When you perform this step, you can run them in parallel to grain time. If you split the steps into multiple release definitions step, it is also clear where you have a problem if a specific step fails and find the issue.
Deploy the production version
The last step will deploy the templates to a location where the build number is used in the naming convention. The task Azure Blob File Copy is the same as in the first step, only the location where the files are copied to is variable, depending on the build number. In this way the templates can be referenced by using the build number in the URL. This way a team that uses your templates can build and test their deployment on a specific version stable version of the templates.
Pipeline for deploying the resource base on the reusable ARM templates
When all linked templates are deployed, they can be used to perform the deployments of your Azure infrastructure. In the sample pipelines, I have only one test environment, but the number of test environments can be different for each pipeline. One pipeline will deploy the resources of one Azure Resource group.
Build
The goal of the build is to produce an artifact of the templates that can be used in the release pipeline. The deployment starts with a pull request to the master branch of the Git repository, which is a trigger for the orchestration to start a new build. In this build pipeline, the sources are copied to a build artifact to be used in a release.
Release
The release pipeline will validate, do a test deployment and then deploy the resource to the production environment. The templates in each environment are the same; the only difference is the parameter files. The parameter file can parameterize the sizes of the resources deployed in the different environments. The sizes must be chosen wisely in order to represent the production environment, but keep in mind the costs of running a test environment. In the main template, you keep a variable build, which you use to point to a specific release from the previous pipeline. In this way you can control the deployed version of your shared linked templates.
Validate templates
The first step consists of validating the templates for all environments. This is done by running a deployment in Validation Mode. You can select this option under Deployment mode in the ARM Deployment task. Here, the template is compiled, it is checked to see whether it is syntactically correct and will be accepted by Azure Resource Manager. You have to do this for all environments to check whether the parameter files are correct. When the step succeeds, the deployment to test will start.
Release test
The goal of this step is to deploy and test the deployment of the resources. If there is a need for a gatekeeper, approvals can be added at the beginning or end of this step. If not, the deployment of your test environment starts automatically. If possible, use the Deployment Mode option “Complete”. This ensures that the resources in the Azure Resource Group are the same as those defined in the ARM template. The action consists of 2 tasks. First create a SAS token for access to the Azure Storage. The next step performs the actual deployment. If everything succeeds, you can optionally do some manual testing on the resource itself, do infrastructure testing with Pester or create some test scripts.
Release production
The production release starts with a gatekeeper (approval). When you are satisfied with the previous (test) resources, an approver can start the production deployment. All resources in the production resource group will be updated according to the ARM template. Try to run your deployment in Complete mode, because then you know that all resources in the resource group are the same as you defined in your Git repository. You are running an infrastructure as Code scenario.
Final thoughts
Setting up deployment pipelines for your ARM templates is an up-front investment aimed at giving you control over the resources that are deployed in your Azure environment. When the pipelines are running, changes to your Azure environment are fully controlled from the code, and all changes are traceable from VSTS.
Peter Groenewegen has been programming computers since he was six. Currently, he focusses on implementing cloud strategies on Microsoft Azure, Software Architecture, DevOps and Application Lifecycle Management. He works as an Azure Cloud Consultant at Xpirit, where he helps clients hands-on with their Cloud implementations. Peter is active on Stackoverflow, writes blogs and speaks at conferences. Follow him on Twitter @pgroene
Comments
- Anonymous
April 01, 2018
Hi Peter,First of all great article!Previously I used to deploy Azure Resources using VSTS build. Typically I created a repository with all parts needed for a complete deployment, using directories for the different Resource Groups. This way I could test templates and deploy them using CI.Can you please tell me in your setup how you handle the separation of parts of a complete deployment? (e.g. 1 part of the deployment contains all network parts and another part containing the VM's depends on the network Resource Group). If your release contains all parts, then a release with all validations can take a huge amount of time, but if parts are separated, test-deploys will fail.Cheers,Christof VG- Anonymous
April 03, 2018
I start with creating a basic directory structure where resources are ordered by there resource type. These are the basic layers from where to build you composition of resources (linked templates). You can have multiple implementations for a resource. Try directly to think in t-shirt sizes (https://pgroene.wordpress.com/2016/09/06/creating-a-t-shirt-size-arm-template/), only expose the minimal set of parameters to keep your test effort smaller (less parameter combinations). Make educated guesses on what can go wrong to make your test set smaller. Next you start combining templates to create a next layer of composed templates and so on. Keep what you can parameterize as small as possible and add only a small number of capabilities to a layer. Sometimes it can be better to make multiple implementation than to try to combine multiple capabilities (keep your complexity small). When testing your templates you only test the capabilities of the new layer (composed template), the underlying layers are tested by there own tests. Each test is a complete deployment of all underlying resources (complete mode) in its own resource group. Test you composed templates in parallel with multiple build agents in their own resource groups to save time. You will also see that when you have the correct composition with linked templates, many resource will deploy in parallel (dependencies are auto discovered, you do not have to specify dependson in you linked resources).
- Anonymous