Anatomy of an ARM Template Part 2
I have worked with Azure infrastructure for over half of my career, and I have used primarily ARM templates. ARM templates allow for repeatable, declarative infrastructure, policy and governance to be deployed to your Azure subscription easily. In this post, I will outline the foundations of ARM templates as I have done several times for clients and in presentations. I hope you walk away having learned one new tip that you can use for your ARM template deployments.
Before we delve into ARM templates, let's start with JSON. Javascript Object Notation is a language that formats data and is primarily used in server-client communications. This makes it perfect for ARM templates because you are essentially sending data to the ARM service, which will then provision your resources. If you have any experience with web development, you may have come across JSON in the past. There are some elements to JSON that dictate the structure of the language: the use of the curly braces, separation of resources using commas among other syntax. These are clearly evident in ARM templates. I am by no means a JSON expert, but knowing the language behind ARM templates can be useful in deciphering the templates themselves.
The schema of an ARM template is as follow:
I will go through each section. Many of these will be familiar, however, there may be sections that you never thought you needed or never used and may find useful.
Schema: This is the fist line of any ARM template and it essentially call out to a service that check to ensure that your template is actual JSON and contains all required sections. This is an iimportant pre-check in order to avoid errors in deployment. Understand that the date notation within this line can change based on the method and scope of deployment. A template deployed tenant-wide with Visual Studio Code may have a different date notation (or API version) than a template deployed to a resource group with a different editor. It is important to test deployments thoroughly to ensure that all desired functionality is working with your template.
contentVersion: I have always called this a poor man's source control. You can place any value in this field. When I come across ARM templates online, it is usually set to 1.0.0.0 and I don't bother changing it becuase I have actual source control tools. You can use this field to keep track of major changes in your template - or not. I would recommend for enterprise deployments using a source control tool instead. You may find it helpful, I have yet to do so.
apiProfile: This was a section that I was not familiar with when i recently reviewed the ARM template schema. ApiProfile is handy for defining the API versions of any resource that will be used in your template. This can be helpful if you only want certain versions of resources in your templates and you want to define this in one place, rather than for each resource. For example, you can define the API version that you want to use for virtual machines and ensure that any virtual machine deployed with your template will use that API version. I do believe it can be helpful as far as ease of use for ARM templates. Surprisingly, not everyone finds reading an ARM template easy! The more you can define in one place in your template, the less time you have to spend making edits when necessary. I like this option a lot.
Parameters and Variables: Some people find it difficult to distinguish between these two elements. A parameter is information that is passed at runtime, just before you deploy your template. A variable is usually hard coded, such as a name for a virtual machine, or it can be dynamically created using parameters, variables, hard coded strings, standard template functions or any combination of the above. both are frequently used within resources for various purposes, however, ARM templates do not require either variables or parameters to be included. The only required section of an ARM template is the resources sections.
Functions: Did you know that you can define your own functions in ARM templates? I find this to be an interesting option. Creating functions is super easy. You define your functions namespace in order to prevent clashing with standard template functions (concat(), reosurceId(), etc.). Within the namespaces you can have member functions that use parameters defined within themselves in order to define their output. You cannot use variables within your function(s), nor can you use reference() or list() functions and there using default values for your function parameters is prohibited. This is another way to define some special operation once in your template and use it in multiple places, reducing the risk for human error so its a great idea to check it out.
Resources: This is the easiest to understand: resources are what you want to deploy. You can deploy almost anything within this sections, including polices, RBAC roles, service principals, and more. Don't make the mistake of thinking that you only have the option of deploying traditional resources!
Outputs: This is the place to define what types of output you want to see for your template. You may want to output the private ip address from a virtual machine so that you don't have to peruse the portal to connect or the name the names of your resources to verify your naming convention. This is a great way to collect information on your resource to keep as a record.
Now that we have an idea of what an ARM template could look like, here are some resources that help us develop ARM templates:
1. resources.azure.com - This is a splendid resource for looking at every single available property of a resource post deployment. With API versions of resources changing constantly, this is a good way to see different properties at a glance. This portal can also help to troubleshoot a stubborn deletion. Once in a blue moon I will have a resource that is stuck deleting. Sometimes I will have the patience to wait and sometimes I need to free up that resource in order to redeploy. When time is of the essence I can go to this portal for force delete a resource. Please be extremely careful when doing this and ensure that you understand any dependencies of resource deletion. There are other useful items in this portal that you can explore on your own, such as PowerShell commands and Ansible playbooks.
2. JSONlint.com - When doing heavy duty work on ARM templates, I prefer Visual Studio Code with the ARM extension. When I am missing a comma and my eye are weary of JSON, I like to pop my template into this time tested JSON validator to see exactly where I am missing it.
3. Export Template - If you go to a resource in the Azure portal and look along the left hand side of the resource page, you are likely to find an option to export the template. Even better, uncheck the 'include parameters' option in this window and you will have an ARM template that is nearly ready for redeployment. This is really helpful for documentation or troubleshooting. It can also provide the starting point for your own template development.
You can find more in-depth information here on ARM template structure: https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-syntax