azure

Azure Resource Manager and ARM templates

Azure Resource Manager:

Azure Resource Manager is the deployment and management service for Azure.You can think of it as a management layer that enables you to create, update, and delete and organize the resources in Azure subscription.

You can create azure resources using one of the following methods.

  1. Azure portal
  2. Azure powershell
  3. Azure CLI
  4. Rest Client

When you create a resource using the above mentioned methods, the Azure Resource Manager API handles your request in the background as a result of which we get  consistent results no matter which method you use to create a resource.

ARM Template:

Azure Resource Manager allows you to provision your resources using a declarative template. In a single template, you can deploy multiple resources along with their dependencies.

ARM template is a JavaScript Object Notation (JSON) file that defines one or more resources to deploy to a resource group or subscription. The template can be used to deploy the resources consistently and repeatedly.

The benefit of using ARM template in your project is mainly 3 fold.

  1. Re-usability: Once you create the ARM template for a resource you can use it multiple times to create same kind of resources with just few changes in the parameters.
  2. Consistency: By using a template, you can repeatedly deploy your solution throughout its lifecycle and have confidence your resources are deployed in a consistent state.
  3. Change tracking: Since ARM templates are json files, you can add it in the source control of your project so that you can leverage all the features of source control like change logs, history of changes, author of the changes etc.

Structure and Syntax of ARM templates:

ARM template has the following structure.

{
“$schema”: “”,
“contentVersion”: “”,
“apiProfile”: “”,
“parameters”: { },
“variables”: { },
“functions”: [ ],
“resources”: [ ],
“outputs”: { }
}

Element name Required Description
$schema Yes Location of the JSON schema file that describes the version of the template language.
contentVersion Yes Version of the template (such as 1.0.0.0). You can provide any value for this element. Use this value to document significant changes in your template.
apiProfile No An API version that serves as a collection of API versions for resource types. Use this value to avoid having to specify API versions for each resource in the template.

For more information, see Track versions using API profiles.

parameters No Values that are provided when deployment is executed to customize resource deployment. It comes handy when we use it in Continuous Deployement pipeline.
variables No Values that are used as JSON fragments in the template to simplify template language expressions.
functions No User-defined functions that are available within the template.
resources Yes Resource types that are deployed or updated in a resource group or subscription.
outputs No Values that are returned after deployment. It comes in handy when we use ARM template in Continuous Deployment pipeline.
  • There are many functions which you can use in ARM templates. You can find more details here. And if you wish to know the syntax of each element, you can go through the links mentioned in the above table.

Types of ARM templates:

  1. Nested Templates
  2. Linked Templates

Nested Templates:

You can deploy multiple resources using one template, by defining the resources one after another. Here you will be having one main template file which will contain the template for all the resources and only one parameter file which will contain all the parameters that will be given as input to the template.

This is advisable if you have less number of resources and there is not much customization involved in  your ARM template. Here is an example of Nested ARM template with parameters.

Limitation: The template file can be of 1 MB max.

Linked Templates:

Linked template comes in handy when

  1. You have large number of services to deploy: When you have a large number of services to deploy, there is a very rare chance that your template file size may go beyond 1MB if you use nested template. It is most unlikely to go beyond 1 MB since these are the JSON files. But using  linked template will increase your readability of code. It will be easy to manage your ARM templates.
  2. You want to reuse the template for multiple deployment: When you want to reuse the template of a resource for multiple deployments, you can leverage the linked template. All you need to do is have a separate parameter file for each deployment which will contain the parameters that you want to use for each deployment.

Here is an example of linked template.

Few tricks and tips:

The basic syntax of the template is JSON. However, below are the few points about how to use different expressions in the template.

  • Expressions start and end with brackets: [ and ], respectively.

For example :

"parameters": {
  "location": {
    "type": "string",
    "defaultValue": "[resourceGroup().location]"
  }
},
  • You can use  functions that Resource Manager provides to use within a template. Function calls are formatted as functionName(arg1,arg2,arg3). The syntax .location retrieves one of the properties (i.e location of the resource) from the object returned by that function.
  • Template functions and their parameters are case-insensitive. For example, Resource Manager resolves variables(‘var1’) and VARIABLES(‘VAR1’) as the same. Unless the function explicitely modifies case (such as toUpper or toLower), the function preserves the case.
  • “demoVar1”: “[[test value]” interpreted as [test value] but “demoVar2”: “[test] value” interpreted as [test] value .
  • To pass a string value as a parameter to a function, use single quotes. For Example:”name”: “[concat(‘storage’, uniqueString(resourceGroup().id))]”
  • To escape double quotes in an expression, such as adding a JSON object in the template, use the backslash. For example:
"tags": {
    "CostCenter": "{\"Dept\":\"Finance\",\"Environment\":\"Production\"}"
},
  • You can use concat function to merge strings.
  • Sometimes,you would need to use some properties of a resource while creating other resources. For example: you would need the resource id of server farm (Microsoft.Web/Serverfarms/<app service plan>) while creating the scale out and scale in settingsyou can use the below syntax to get the resource id of server farm.[resourceId(‘Microsoft.Web/serverFarms/’, parameters(‘svcPlanName’))]
  • reference : 

When you need to get the properties of the resources you would need to use the reference function.

  • For example:
     
    > To get the instrumentation key of application insight :
    [reference(resourceId('microsoft.insights/components/', parameters('AppInsights_name')), '2015-05-01').InstrumentationKey]
    > To get the app id of application insight : 
    [reference(resourceId('Microsoft.Insights/components/', parameters('AppInsights_name')), '2015-05-01').AppId]
    > To get the web app url of a deployment slot in app service :
    [concat('https://', reference(resourceId('Microsoft.Web/Sites/Slots', parameters('webAppName'),variables('SlotName')),'2018-11-01').defaultHostName)]
    > To get the web app url in app serivce : 
    [concat('https://', reference(resourceId('Microsoft.Web/Sites', parameters('webAppName')),'2018-11-01').defaultHostName)]
  • You can also use reference function to use the different values from other linked templates. You can find the example of this here . In this example, you can see that it is using the output values of application insight linked template in main template using reference function.
  • Condition:When you must decide during deployment whether to create a resource, use the condition element. The value for this element resolves to true or false. When the value is true, the resource is created. When the value is false, the resource isn’t created. The value can only be applied to the whole resource.Typically, you use this value when you want to create a new resource or use an existing one. For example, to specify whether a new storage account is deployed or an existing storage account is used, use:
  • {
        "condition": "[equals(parameters('newOrExisting'),'new')]",
        "type": "Microsoft.Storage/storageAccounts",
        "name": "[variables('storageAccountName')]",
        "apiVersion": "2017-06-01",
        "location": "[resourceGroup().location]",
        "sku": {
            "name": "[variables('storageAccountType')]"
        },
        "kind": "Storage",
        "properties": {}
    }
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "apiVersion": "2016-01-01",
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[concat('storage', copyIndex(1))]",
      "location": "[resourceGroup().location]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {},
      "copy": {
        "name": "storagecopy",
        "count": 3
      }
    }
  ],
  "outputs": {}
}

Note: In the above example copyIndex value will start from 1. If you do not mention the offset value it will start from 0. Which means your storage names will be storage0, storage1, storage2.

> To create WebApp1Storage, FunctionApp1Storage, WebApp2Storage, FunctionApp2Storage

"parameters": { 
  "apps": { 
    "type": "array", 
    "defaultValue": [ 
      "WebApp1", 
      "FunctionApp1", 
      "WebApp2",
      "FunctionApp2" 
    ] 
  }
}, 
"resources": [ 
  { 
    "name": "[concat('storage', parameters('apps')[copyIndex()])]", 
    "copy": { 
      "name": "storagecopy", 
      "count": "[length(parameters('apps'))]" 
      "mode": "serial",
      "batchSize": 2
    }, 
    ...
  } 
]

By default, Resource Manager creates the resources in parallel. The order in which they’re created isn’t guaranteed. However, you may want to specify that the resources are deployed in sequence. For example, when updating a production environment, you may want to stagger the updates so only a certain number are updated at any one time.

To serially deploy more than one instance of a resource, set mode to serial and batchSize to the number of instances to deploy at a time. With serial mode, Resource Manager creates a dependency on earlier instances in the loop, so it doesn’t start one batch until the previous batch completes.

You can find more details about copy here.

I have tried to note down all the basic information one would need while creating an ARM template. However there is much more to ARM template than this. Feel free to suggest any feature or functionality you want me to add to this blog.

Happy learning 🙂

References:

https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#resource-iteration

https://github.com/Azure/azure-quickstart-templates/tree/master/monitor-autoscale-webappserviceplan-simplemetricbased#start-of-content

https://docs.microsoft.com/en-us/azure/templates/microsoft.web/2018-02-01/serverfarms

https://docs.microsoft.com/en-in/azure/azure-resource-manager/resource-group-template-functions

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s