Provisioning with Azure Resource Manager templates
Provisioning cloud resources
- Working on bigger cloud project where you need to provision lots of stuff
- Working with the team
- You need to create additional environments and cloud infrastructure should be the same
Fortunately for Azure we have Azure Resource Manager templates which help to address the issues described above. Note that there are also other tools available for performing this task e.g. Terraform - however these are out of scope for this article.
What is Azure Resource Manager (ARM)?
- Azure Portal
- SDK's
- REST API's
- Command line tools
One of the benefits of ARM is that it allows you to manage you infrastructure with so called templates - these are JSON's containing definition of resources to be created/updated. This article will describe format and some basic features of ARM templates through simple example of creating Azure Storage Account with Blob container.
Login to Azure and setup default subscription
az login
Next step will be setting default subscription - it is the subscription used by default when using the tool so that you don't have to provide it explicitly. In case you would like to use different subscription you will need to change default setting or explicitly provide different one.
az account list --output table
az account set --subscription "Subscription of your choice"
Create Resource Group
az group create --location eastus --name my-infra-rg
After successfully finishing its job, the above command should provide output similar to one on the screenshot below.
The information which is important here are:
- id - this is resource Id of the resource group you have just created. It includes subscription Id, which I obfuscated on the screenshot.
- properties.provisioningState - this property informs you about the status of the provisioning. In this case it was successful.
Create ARM template
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"functions": [],
"variables": {},
"resources": [],
"outputs": {}
}
- parameters - contains values which allow you to re-use template e.g. across different environments
- functions - ARM templates do contains lots of built-in helper functions which allow you to e.g. operate on text strings, extract keys and connection strings from other resources. Full list of available functions is available here. The property contains so called user-defined functions which are compositions of built in functions.
- variables - contains variables which you want to re-use inside your template. It is especially useful in case of values computed with functions.
- resources - this is the most important property, it is where you define Azure resources to be created.
- outputs - contains values you want to... well output after deployment. If the template is so called linked template (this is out of scope for this post, in short this is option for re-using templates), values listed in output section can be used in template which references linked templated. You can also use it when executing some automation.
Add Storage Account with Blob container
{
"name": "provisionwarmtemplate",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"tags": {
"displayName": "provisioningWithArmTemplatesSA"
},
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"resources": [
{
"type": "blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat('default/', 'my-storage-container')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', 'provisionwarmtemplate')]"
]
}
]
}
- It is creating two resources Storage Account with name provisionwarmtemplate and Blob container my-storage-container which is nested resource dependent on the Storage Account.
- For Storage Account we are setting location property which will define region where it will be deployed. The location is set with use of function resourceGroup() which returns object describing resource group in which resource is being deployed. Luckily for us this object does contain location property. It is important to note that the function is only available when deploying at Resource Group level. If the value is being set with functions, the string is wrapped with square braces - when using Visual Studio Code extension for ARM, you will get syntax highlighting and completion for these.
- Blob container my-storage-container is added as a nested resource to Storage Account - because of that it has to include dependsOn property. The property instructs Azure Resource Manager that it should create Storage Account first and then Blob container. This has to be explicitly set for nested resources. Similarly to location, the value is set with function - in this case it is resourceId function which resolves Id of the resources. First argument of the function is resource type, the second one resource name.
- Both resources do include apiVersion property - it defines which version of the API should be used for handling deployment of specific resources. Each resource has its own distinct set of API versions. Newer versions of the API can have some additional features, on the other hand they may deprecate others.
Refactoring
- Name of the Storage Account
- Name of the Blob container
- Location of Storage Account - it is set to the same location as Resource Group where you are deploying
"parameters": {
"storageAccountName": {
"type": "string",
"metadata": {
"description": "Storage Account name"
}
}
}
- type - which defines type of the property value. You can fined complete list of types here.
- metadata.description - description of the parameter - it is useful when you want to provide more information about how the parameter is being used.
The final step for the refactoring is creating parameters file which will be used when deploying resources. Create azuredeploy.parameters.json and paste snippet below into its content.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"value": "provisionwarmtemplate"
},
"location": {
"value": "eastus"
},
"containerName": {
"value": "my-storage-container"
}
}
}
Deployment
az deployment group create --resource-group my-infra-rg --template-file .\azuredeploy.json --parameters .\azuredeploy.parameters.json
az storage account list --query "[?resourceGroup == 'my-infra-rg'].{Name:name, Location:location, ResourceGroup:resourceGroup}" --output table
az group delete --name my-infra-rg
That's it for this article. Now you can go and play by creating template for e.g. project you are working on right now. There are tons of information about Azure Resource Manager in Microsoft docs (linked in More reading section below) and azure-quickstart-templates GitHub repository does contain some sample templates for provisioning common resources.