ARM templates are very popular these days…
…and many of my customers use them regularly, but only very few realise their full potential.
Three things you might not know
- You can roll out a set of company-owned templates via VSTS on a regular basis with a service account
- You can reference sub templates by using a deployment resource in your template. You can set dependencies, inputs, and outputs just like you would for a normal resource deployment.
- You can store ARM templates in source control and use them to deploy your infrastructure when you deploy your code to always work off a known environment.
Child & Parent Templates explained
A feature that is often heavily underused is the ability to create nested templates.
This allows you to create conditions and optional deployments as well as extension deployments.
This is how I explain the different types of template files you can have in a multi-file deployment. I have listed them in the order of deployment.
- Parameters file
- This is the most commonly used secondary file. You can define your parameter values here and also link to KeyVault.
- Main Template
- This is the template from where you would kick your deployment off. In a multi tiered deployment this would mostly contain deployment resources.
- Template Meta Data file
- If you are looking to publish your template you may want to complete a meta data file that describes what it does and links to icons and pictures associated with the deployment. (This file is not necessary for the actual deployment)
- Shared Resource Template
- These are resources that other resources in our deployment need to function properly.
- Examples include but are not limited to: KeyVault(s), networks, storage, service bus queues, DBaaS server, app service plan
- Optional Templates
- These can come up at any stage during the deployment
- Usually we would prompt the user to select an option in a parameter (for example: DeploySecondaryReplica which could be answered with “WestEurope”, “NorthEurope”, or “DoNotDeploy”)
- We stick this variable into a “deployment” resource’s template uri setting which causes:
- The “DeploySecondaryReplica_WestEurope.json” to be called for a sub deployment if the option was selected, which will cause a secondary deployment in West Europe (most likely with additional9 sub deployments)
- The “DeploySecondaryReplica_NorthEurope.json” to be called for a sub deployment if the option was selected. Similarly to the first option this would kick a different template that spins up the secondary replica in a different location.
- Finally “DeploySecondaryReplica_DoNotDeploy.json” would call an empty template that would let the rest of the deployment continue, while stopping the creation of a secondary replica during this deployment.
- Known Configuration
- These are the essentials that your app needs to function (once shared components are up)
- In a PaaS deployment this might be: web app, api app, database
- Member Resource Templates
- These are extensions and/or resources that get deployed within traditional resources
- For example: Source Control plugin for web apps
- They can be split into “custom scripts” which is usually only used against a specific resource and “reusable scripts” that might apply to more than one resource.
- The distinction is there mostly because the design process of a reusable script will have a large focus on parameterisation or loops, while this is not as important for custom scripts.
Incremental or Complete
A complete deployment will let you start from a clean slate, deploying all resources from fresh. (you will see an appropriate warning) An incremental deployment will try to update as much as it can and avoid redeployments whenever possible.
Best Practice Guidelines for ARM templates
- Think twice about making API Version a variable or even a parameter
- schema versions change over time, which means that your template could break in the future if the api version is modular
- your template will be rewritten at the point of deployment to comply with the latest API version
- you can combine more than one API version in a template
- Location should be set with resourceGroup().location when possible.
- if you use a location parameter, use it consistently
- mixing the function and a parameter can lead to problems if a user decides to deploy into a resource group where the location does not match the resource group location
- although this is possible – by design – it is inadvisable as using different locations for resource groups and their resources can seem confusing
- Use the securestring or Azure Key Vault for all passwords and secrets
- there is a secretObject wrapper as well for multipart variables
- Minimize parameters when possible
- too many parameters can confuse the user.
- when using parameters make sure that they are restricted so that deployments cannot be broken easily due to a wrong parameter
- Take advantage of the comments element
- if you use Visual Studio to deploy any C# comments will be stripped from your template prior to the deployment
- if you use any other IDE using C# or any other comments will cause a deployment error
- all schemas have “comments” elements to allow you to persist comments into the template and maintain the flow of JSON around the comment
- Always use reference() and resourceId() over hardcoded endpoints and IDs
- Output any newly created endpoints (e.g. public IPs)
- More generally: Outputs can also be used to enable the parent template to use things the child template has created
- Consider using a JSON validator (for example in the Azure Portal) and automated formatting for better readability
- If you use Visual Studio or Visual Studio Code a lot of this is done for you
- Consider allowing the user to specify prefixes and/or suffixes for all resources that are going to be created during the course of the template deployment
- This works well if your template is designed to spin up different environment types or different regional copies that need to be easily identifiable (e.g. uksouth-mywebapp-uat)