ARM stands for Azure Resource Manager. We use ARM templates to deploy resources to Azure. We can automate deployments and use the infrastructure as code. In code, we define the infrastructure that needs to be deployed. The infrastructure code becomes part of our project. Like the application code, we store the infrastructure code in a repository and version it. We use this approach because anyone on the team can run the code and deploy similar environments.
To implement infrastructure as code for Azure solutions, we use Azure Resource Manager (ARM) templates. The template is a JSON file that defines the infrastructure and configuration. In the template, we specify the resources to deploy and the properties for those resources. The template uses declarative syntax, which lets you deploy without having to write the sequence of programming commands to create it.
Template file
The template has the following sections,
- Parameters- We can provide values during deployment that allow the same template to be used for different Environments.
- Variables- These values can be reused in templated and can be formed from parameter values.
- User-defined functions- Create functions that simplify our template.
- Resources- Resources that are to be deployed
- Outputs- Return values from the deployed resources.
Below is a sample template file that creates a Storage Account, Azure App Service Plan & Web App.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters":{
"storagePrefixForArm":{
"type": "string",
"minLength": 3,
"maxLength": 24
},
"appServicePlanName": {
"type": "string",
"defaultValue": "exampleplan1"
},
"location":{
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"webAppName": {
"type": "string",
"metadata": {
"description": "web app name and app service plan "
},
"minLength": 2
},
"linuxFxVersion": {
"type": "string",
"defaultValue": "php|7.0",
"metadata": {
"description": "Current Web App"
}
},
"storageSKU":{
"type":"string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Standard_ZRS",
"Premium_LRS",
"Premium_ZRS",
"Standard_GZRS",
"Standard_RAGZRS"
]
},
"resourceTags": {
"type": "object",
"defaultValue": {
"Environment": "Dev",
"Project": "ARMTemp"
}
}
},
"variables":{
"uniqueStorageName":"[concat(parameters('storagePrefixForArm'),uniqueString(resourceGroup().id))]",
"webAppPortalName": "[concat(parameters('webAppName'), uniqueString(resourceGroup().id))]"
},
"resources": [{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('uniqueStorageName')]",
"location": "[parameters('location')]",
"tags": "[parameters('resourceTags')]",
"sku": {
"name": "[parameters('storageSKU')]"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true
}
}, {
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"name": "[parameters('appServicePlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "B1",
"tier": "Basic",
"size": "B1",
"family": "B",
"capacity": 1
},
"kind": "linux",
"properties": {
"perSiteScaling": false,
"reserved": true,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
}, {
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('webAppPortalName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]"
],
"kind": "app",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"siteConfig": {
"linuxFxVersion": "[parameters('linuxFxVersion')]"
}
}
}],
"outputs": {
"storageEndpoint": {
"type": "object",
"value": "[reference(variables('uniqueStorageName')).primaryEndpoints]"
}
}
}
JavaScriptCopy
Let’s Deep dive into the template file for each section.
$schema
Specifies the location of the JSON schema file. The schema file describes the properties that are available within a template.
contentVersion
Specifies the version of the template you are creating, and value is used for versioning for the significant changes of your template.
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
HTTPCopy
Resources
This section specifies the resources which you are deploying. In the below example, we are creating an Azure Storage account using ARM Template.
- type- refers to the Azure Resource we are creating, which in the example below is “Microsoft.Storage/storageAccounts”
- apiVersion- refers to the REST API version we use to create the Azure resource using the ARM Template, and apiVersion is specific to the Azure resource we are creating.
- location- location refers to the location we want to create the Azure resource. (Central US or Central India)
The other properties are specific to the resource which we are creating. If we consider Azure Storage Account, we have kind and properties.
"resources": [{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('uniqueStorageName')]",
"location": "[parameters('location')]",
"tags": "[parameters('resourceTags')]",
"sku": {
"name": "[parameters('storageSKU')]"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true
}
}
JavaScriptCopy
Parameters
These are the i/p values that can be provided while executing the arm template. Parameters help us provide values at runtime and help us reuse the arm template for many purposes.
If we consider storagePrefix, it has type(dataType), minLength, and maxLength properties. Similarly, we can use the defaultValue property for assigning the default value when no value is not supplied at run time. Below are the parameters which are defined in the arm template.
We can also use some predefined template functions in the parameters. For Example, if we consider the location parameter, it has defaultValue, which is [resourceGroup().location], which means we have to create the storage account in the same location as the Azure resource group. We call these functions template functions.
We also have the allowedValues property, which provides only the values from the set of values. At runtime, if a value is provided which is not from allowedValues, an exception will raise.
"parameters":{
"storagePrefixForARM":{
"type": "string",
"minLength": 3,
"maxLength": 24
},
"storageSKU":{
"type":"string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Standard_ZRS",
"Premium_LRS",
"Premium_ZRS",
"Standard_GZRS",
"Standard_RAGZRS"
]
},
"location":{
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
}
JavaScriptCopy
Now let’s see how to retrieve values from the parameters and use them in the resources objects. We can use the parameters function by sending the parameter name to access the parameter value.
"location": "[parameters('location')]",
JavaScriptCopy
Variables
"variables":{
"uniqueStorageName":"[concat(parameters('storagePrefix'),uniqueString(resourceGroup().id))]",
"webAppPortalName": "[concat(parameters('webAppName'), uniqueString(resourceGroup().id))]"
}
JavaScriptCopy
We can access the variables similarly to the parameters.
"name": "[variables('uniqueStorageName')]"
JavaScriptCopy
Outputs
Outputs are the values of the deployed resource. We use outputs when you need a value from a deployed resource.
In the below example, a return type is an object, and we are using a template function reference to get the runtime state of the deployed Azure resource by passing the name of the deployed resource. In the below example, we are getting primaryEndpoints of the storage account.
"outputs": {
"storageEndpoint": {
"type": "object",
"value": "[reference(variables('uniqueStorageName')).primaryEndpoints]"
}
}
JavaScriptCopy
Tags
We can add the tags to the Azure resource we are creating by defining the tags in the parameters section and then using the parameter value in the resource template.
"resourceTags": {
"type": "object",
"defaultValue": {
"Environment": "Dev",
"Project": "Tutorial"
}
JavaScriptCopy
Defining tags property for the resource.
"tags": "[parameters('resourceTags')]",
JavaScriptCopy
We can deploy the arm template from the Azure CLI cmd prompt. Upload the arm.json file to the Azure cloud shell and execute the below command for execution.
If we check the Azure resource group and deployment tab, we can see the arm template with the template name.
Summary
The declarative syntax of ARM templates includes sections describing outputs, user-defined functions, parameter values, and resources to deploy. Infrastructure as code for Azure solutions can be implemented with the help of the template. The material includes a sample template file for setting up a storage account, an app service plan for Azure, and a web app.
About the Author
Asp.net, Sql Server MVC, JavaScript Angular, Ionic, Alexa Skills
Reference
Sai Krishna, D., 2023,Introduction to Azure ARM Template, C-sharpcorner.com, Available at: https://www.c-sharpcorner.com/blogs/introduction-to-azure-arm-template [Accessed on 4 July 2023]