In January I did a presentation at LEAP 2020 on “The Ultimate ARM Template”. The sessions weren’t recorded so when someone asked about it I offered to try to get the content out… It’s taken a while because I kept thinking how long this post would be (and procrastinating) so I eventually figured out I could just break it up to get started.
What is “The Ultimate ARM Template”? I had no idea when I started (I didn’t pick the topic for LEAP) but eventually came up with this:
A declarative statement of the goal state for your Azure Infrastructure and Configuration
OK, that describes pretty much any ARM Template, so what should the ultimate one do?
- Utilize available language constructs to maximize the impact of minimal code
- One Template for n Scenarios – achieving the right balance based on the life cycle of the resources (i.e. don’t just put everything in the same template)
- Under Source Code Control 😉 (With unit tests (parameter files))
Why bother with templates? There are many other ways to do this sort of thing (Infrastructure as Code) – CLI Tools, SDKs, Terraform, even the Azure Portal and may seem easier at first glance. What’s unique about templates?
An ARM template creates a deployment of multiple resources orchestrated by Azure in the native language of the platform
- A single deployment can deploy to multiple “scopes” (Resource Group, Subscription, Management Group and Tenant)
- The template deployment is validated and checked for errors before any resource is created
- The orchestration is captured as deployment history that can be used for debugging, auditing, logging
The nice thing about templates is that the platform (not you or tooling) handles all of this.
Key Constructs and Patterns
The patterns you can use across all templates are fairly finite and simple constructs. Even though a template is a simple declarative statement, environments are not always that simple, so expressing them cleanly and concisely can be a challenge. These constructs make your code more flexible but also more concise. Here are those constructs and patterns.
Parameters Add Flexibility
Parameters allow you to change common settings or properties in a template deployment. Default Values can be used to simplify this flexibility. When default values are considered together (often one parameter value depends on another) a template with many parameters defined may only need one or two supplied for most deployments. Smart defaults can also remove the need for conditional statements later in the template. Blank values can be used for optional parameters rather than coupling actual values with switch parameters.
Determine which properties for which resources are “flexible” and which are “standard”. Simplify the sophistication of Azure in your code. For example, VM Disks can be managed, unmanaged or ephemeral. Do you need to provide an option for all three? Also, any property on any resource can be “null” which makes is easy to flip options on and off without duplicating resource definitions.
Copying and Looping
Copy loops have been around for a while, but only recently have we extended the capability to span everything resources, properties, variables and outputs. Recently we added the ability to use zero to any of the above.
Binary conditions can be applied to just about any property in the JSON from a defaultValue on a parameter, to resource properties, to outputs. By applying “null” to a condition many properties can become optional, empty or simply the platform default.
Case/Switch and Object Arrays
JSON object arrays can be used to emulate the behavior of switch statements to simplify look-ups or complex conditionals. If you’ve every needed (or tried) nested if statements this will give you much cleaner, simpler code.
A host of other simple programming expressions can be leveraged for string manipulation, simple arithmetic or logical operations to round out the flexibility needed for any deployment scenario.
The Ultimate Template
That gives you an idea of the tools and patterns that allow you to get the most out of the template language and templates. The template we talked about at LEAP is here along with templates that make use of that template. Another example of how templates like these can be used is as modules which you can see in the QuickStart repo. There are a few QuickStart samples that consume them if you want to see both production and consumption.
In the next post I’ll start walking through that template and how and why the constructs and patterns are applied. In the meantime, if you have any thoughts feel free to leave a comment below.