ARM templates

Some of the prominent advantages of IaC is that it can be version-controlled. It can be reused across environments, which provides a high degree of consistency and predictability in deployments. It also ensures that the impact and result of deploying an ARM template is the same no matter the number of times the template is deployed. This feature is known as idempotent template.

ARM templates debuted with the introduction of the ARM specification and have been getting richer in features and more mature since then. It's important to understand that there's generally a feature gap of a few weeks to a couple of months between the actual resource configuration and the availability of this configuration in ARM templates.

The resource has its own configuration. This configuration can be affected in a multitude of ways, including using Azure PowerShell, Azure CLI, Azure SDKs, REST API, and ARM templates.

Each of these ways has their own development and release life cycle, which is different from the actual resource development. Let's try to understand this with the help of an example.

The Azure databricks resource has its own cadence and development life cycle. The consumers of this resource have their own development life cycle, which is different from the actual resource development. If databricks gets its first release on December 31st, the Azure PowerShell cmdlets for it might not be available on the same date and they might get released January 31st of the next year; similarly, the availability of these features in the REST API and ARM templates might be around January 15th.

ARM templates are JSON-based documents that, when executed, invoke REST API on the Azure management plane and submit the entire document to it. The REST API has its own development life cycle, and the JSON schema for the resource has its own life cycle.

It means Azure development of a feature within a resource should happen in at least three different components before they can be consumed from ARM templates. These include the following:

Each resource in the ARM template has the apiVersion property. This property helps to decide the REST API version that should be used to provision and deploy the resource. The next diagram shows the flow of requests from the ARM template to resource APIs that are responsible for the creation, updation, and deletion of resources:

A resource configuration, such as a storage account in ARM template, looks as follows:

{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2017-06-01",
"name": "[variables('storage2')]",
"location": "[resourceGroup().location]",
"kind": "Storage",
"sku": {
"name": "Standard_LRS"
}
}

In this code listing, the availability of this schema for defining sku is based in the development of the ARM template schema. The availability of the REST API and its version number is determined by the apiVersion, which happens to be 2017-06-01. The actual resource is determined by the type property, which has the following two parts:

In this case, the resource is identified by its provider name and type, which happens to be Microsoft.Storage/storageaccounts.

Until recently, ARM templates expected resource groups to be available prior to their deployment. They were also limited to deploying to a single resource group within a single subscription.

This means that, until recently, an ARM template could deploy all resources within a single resource group. This was the practice for years, until recently Azure announced that a single ARM template could be used for deploying resources to multiple resource groups within the same subscription of multiple subscriptions simultaneously. It's now possible to create resource groups as part of ARM templates, which means it's now possible to deploy resources to multiple regions into different resource groups.

Why would we need to create resource groups from within ARM templates, and why would we need cross-subscription and resource-group deployments simultaneously?

To appreciate the value of creating resource group and cross-subscription deployments, we need to understand how deployments were carried out prior to these features being available.

To deploy an ARM template, a resource group is a prerequisite. Resource groups should be created prior to the deployment of a template. Developers use PowerShell, the Azure CLI, or the REST API to create resource groups and then initiate the deployment of ARM templates. This means that any end-to-end deployment  consists of multiple steps. The first step is the provision of the resource group and the next step is deployment of the ARM template to newly created resource group. These steps could be executed using a single PowerShell script or individual steps from the PowerShell command line. The PowerShell script should implement exception handling, compensating code, rollback at a minimum until it's enterprise ready. It is important to note that resource groups can be deleted from Azure and the next time the script runs they might be expected to be available.  It would fail because it might assume that the resource group exists. In short, the deployment of the ARM template to a resource group should be an atomic step rather than multiple steps.

Compare this with the ability to create resource groups and its constituent resources together within the same ARM templates. Whenever you deploy the template, it ensures that the resource groups are created if they don't yet exist, and continues to deploy resources to them after creation.

Let's also understand how these new features can help to remove some of the technical constraints related to disaster-recovery sites.

Prior to these features, if you had to deploy a solution that was designed with disaster recovery in mind, there were two separate deployments: one deployment for the primary region and another deployment for the secondary region. For example, if you were deploying an ASP.NET MVC application using App Services, you would create an app service and configure it for the primary region, and then you would conduct another deployment with the same template to another region with the same configuration.

With the availability of cross-subscription and resource-group deployment, it's possible to create the disaster-recovery site at the same time as the primary site. This eliminates two deployments and ensures that the same configuration can be used on multiple sites.