Azure Resource Manager (ARM) Template Tutorial

Learn how to define and deploy your Azure infrastructure using ARM templates.

1. Introduction to ARM Templates

Azure Resource Manager (ARM) templates are JSON files that declaratively define the infrastructure and configuration for your Azure solution. You can use templates to deploy resources consistently and repeatedly. An ARM template is a set of JSON files that defines the deployment, including:

This tutorial will guide you through the process of creating and deploying a simple ARM template to set up a virtual machine in Azure.

Note: ARM templates offer a powerful way to automate your Azure deployments, ensuring consistency and reducing manual errors.

2. Anatomy of an ARM Template

An ARM template has a structured JSON format. The main sections include:

Here's a basic structure:

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {},
      "variables": {},
      "resources": [],
      "outputs": {}
    }
            

3. Step-by-Step Deployment

3.1. Create a Resource Group

Before deploying any resources, you need a resource group to contain them. You can create one using the Azure portal, Azure CLI, or PowerShell.

Using Azure CLI:

az group create --name myResourceGroup --location eastus

This command creates a resource group named myResourceGroup in the eastus region.

3.2. Define Your Resources

Let's create a simple ARM template that deploys a Storage Account.

Create a file named storageAccountTemplate.json and add the following content:


{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "metadata": {
        "description": "Name for the storage account. Must be globally unique."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for the storage account."
      }
    },
    "skuName": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Standard_ZRS",
        "Premium_LRS",
        "Premium_ZRS"
      ],
      "metadata": {
        "description": "Specifies the SKU name for the storage account."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-09-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('skuName')]"
      },
      "kind": "StorageV2",
      "properties": {}
    }
  ],
  "outputs": {
    "storageAccountNameOutput": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').primaryEndpoints.blob]"
    }
  }
}
                

3.3. Deploy the Template

Now, deploy the template using the Azure CLI. You'll need to provide a unique name for your storage account.

Using Azure CLI:


az deployment group create \
  --resource-group myResourceGroup \
  --template-file storageAccountTemplate.json \
  --parameters storageAccountName=mystorageaccount$(openssl rand -hex 4) \
             skuName=Standard_LRS
                
Tip: The $(openssl rand -hex 4) is a simple way to generate a random suffix for the storage account name, making it more likely to be unique.

This command deploys the template to the myResourceGroup resource group. The output will include the primary blob endpoint of the newly created storage account.

4. Parameters

Parameters allow you to provide input values when deploying a template. They make your templates reusable and flexible.

In our example, storageAccountName, location, and skuName are parameters.

5. Variables

Variables are used to define values that are used multiple times within your template. They simplify your template and make it more readable.

For example, you could define a variable for a common network configuration:


"variables": {
  "virtualNetworkName": "myVNet",
  "subnetName": "mySubnet",
  "vmSize": "Standard_DS1_v2"
}
            

Then, use them in the resources section:


"resources": [
  {
    "type": "Microsoft.Network/virtualNetworks",
    "apiVersion": "2020-11-01",
    "name": "[variables('virtualNetworkName')]",
    // ... other properties
  }
]
            

6. Outputs

Outputs allow you to return values from your deployment. This is useful for retrieving information about the deployed resources, such as connection strings, IP addresses, or resource IDs.

In our template, we output the primary blob endpoint of the storage account:


"outputs": {
  "storageAccountNameOutput": {
    "type": "string",
    "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').primaryEndpoints.blob]"
  }
}
            

The reference() function is used to get information about an existing resource.

7. Best Practices

Consider using template functions like concat(), uniqueString(), and listKeys() to build dynamic resource names and retrieve resource properties.

8. Next Steps

Congratulations on completing this basic ARM template tutorial! Here are some suggestions for further learning: