Raywon Kari - Published on July 14, 2020 - 10 min read
Infrastructure as Code (IaC), is a practice which enables the use of automation to manage resources declaratively such as provisioning, configuring, updating, de-commissioning etc. More theory around this topic can be found on wikipedia. IaC practises have gained a lot of popularity because it brings lot of consistency, predictability, reusability into the system.
Since this is the cloud era at the moment, cloud providers more or less have given the same ability to use IaC practises to manage cloud infrastructure, and IaC in Azure is powered by a service called Resource Manager. Using it, we declaratively define cloud resources in JSON 📃 templates and deploy them to Azure. Rest is taken care by the service itself.
In this blog post, we will explore the basics of Azure Resource Manager (ARM), how to use it by taking an example and some tips & tricks.
It is important to understand how Azure works and the scope of it. Azure provides four levels of scope:
We can apply settings at any of these levels, and the level we select, defines how widely those settings are applied. Also lower levels inherit settings from higher levels such as policies etc.
If we try to understand from the lower scopes, all cloud resources are grouped into resource groups. Resource groups are part of subscriptions, and subscriptions are organised and managed by management groups. If we configure any policies or settings in management groups, those are enforced all the way down to the resource level.
Following diagram illustrates how Azure organises and manages resources.
When we go out to a restaurant, what do we usually do 🍛 ?
We tell what we want to eat, we get the food 😄 and at the end we pay the bill.
That is exactly what is happening with Resource Manager as well. We tell what we want in the templates, we upload the template, and it creates and configures the stuff for us. So writing the template is ordering the food, creating and configuring the resources is getting the food, and paying the bill here is the common aspect 😉.
Resource manager is primarily used to manage azure resources. Whenever we send a request to resource manager either using CLI, or APIs, it authenticates and authorizes the request, resource manager thereafter sends the request to Azure, which takes the request and handles it. Since all the user requests are handled by the same API, resource manager comes with a consistent behavior.
Resource manager is powered by JSON templates 📃. In the templates, one or more resources are defined declaratively to deploy into resource groups, subscriptions, management groups or tenants. Once we have a template, we simply submit it to Resource manager, and it performs operations specified declaratively in the template.
Following diagram is an example of how Resource Manager works.
A Template is the heart of ARM service, therefore it is important to understand the format and how to write a template. A template can consist of the following sections:
Here is an example format of the template in JSON:
{"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#","contentVersion": "1.0.0.0","parameters": {...},"variables": {...},"resources": [...],"outputs": {...}}
Detailed documentation on templates can be found here.
In this blog post, we will create a webapp, and deploy a default .net website to it, using ARM templates. By the end of it, we will see how to use templates to spin up resources.
First of, we create a JSON file named deploy.json
.
We will need a schema, contentVersion, parameters, variables, resources sections in it.
In the parameters section, we will define the name of the webapp, location, sku, the git repo to deploy. In the resources section, we will define the web app plan and the web app.
Here is how the parameters section will look like:
"webAppName": {"type": "string","defaultValue": "raywon-web-app","metadata": {"description": "Web app name."},"minLength": 2},"location": {"type": "string","defaultValue": "[resourceGroup().location]","metadata": {"description": "Location for all resources."}},"sku": {"type": "string","defaultValue": "F1","metadata": {"description": "The SKU of App Service Plan."}},"repoUrl": {"type": "string","defaultValue": "https://github.com/Azure-Samples/app-service-web-dotnet-get-started","metadata": {"description": "Optional Git Repo URL, if empty a 'hello world' app will be deploy from the Azure-Samples repo"}}
Here is how the resources section will look like:
{"apiVersion": "2019-08-01","type": "Microsoft.Web/serverfarms","name": "[variables('appServicePlanPortalName')]","location": "[parameters('location')]","sku": {"name": "[parameters('sku')]"}},{"apiVersion": "2019-08-01","type": "Microsoft.Web/sites","name": "[parameters('webAppName')]","location": "[parameters('location')]","dependsOn": ["[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]"],"properties": {"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]"},"resources": [{"type": "sourcecontrols","apiVersion": "2019-08-01","name": "web","location": "[parameters('location')]","dependsOn": ["[resourceId('Microsoft.Web/sites', parameters('webAppName'))]"],"properties": {"repoUrl": "[parameters('repoUrl')]","branch": "master","isManualIntegration": true}}]}
One common thing we can observe in both these sections is how we are referencing the values of paramters and variables to fetch the actual values. For example:
parameters('location')# This will fetch the location value from parameters sectionvariables('appServicePlanPortalName')# This will fetch the appServicePlanPortalName value from the variables section
Full template can be found here.
Now that we have our template ready, lets try to upload the template to Azure first. We will use the Azure CLI. For instructions on how to install Azure CLI, Refer here
In order to use azure CLI, we need to first auth ourselves with azure using the az login
command, which will open a browser, we then need to login to our azure account.
Once that is done successfully, our CLI session is then ready to use against azure.
Simply run in your terminal:
# This command will not work if# you have MFA enabled.az login# If you have enabled MFA,# fetch your tenant ID and# Use the following commandaz login --tenant TENANT_ID
Tenant ID can be usually found in the Active Directory service in Azure here.
Once az login is done, we should see a response like this:
You have logged in. Now let us find all the subscriptions to which you have access...[{"cloudName": "AzureCloud","homeTenantId": "XXXXXXXX","id": "XXXXXXXXX","isDefault": true,"managedByTenants": [],"name": "Raywon's Azure","state": "Enabled","tenantId": "XXXXXXXX","user": {"name": "its@raywonkari.com","type": "user"}}]
Before creating any azure resources, we need a resource group i.e., kind of a parent container, where the resources will reside.
Lets create a resource group using the following command:
az group create \--name rg-raywon-web-app--location "North Europe"# We should get a JSON response as follows{"id": "/subscriptions/xxxx/resourceGroups/rg-raywon-web-app","location": "northeurope","managedBy": null,"name": "rg-raywon-web-app","properties": {"provisioningState": "Succeeded"},"tags": null,"type": "Microsoft.Resources/resourceGroups"}
As we can see from the provisioning state, the resource group creation has succeeded.
Now lets try to deploy our resources using the template.
TEMPLATE_FILE="./deploy.json"az deployment group create \--name raywon-web-app-template \--resource-group rg-raywon-web-app \--template $TEMPLATE_FILE# This command will take a minute
Once the command exits, we will get a big JSON response, and if we search for privisioning state, we should be able to see if the deployment has succeeded or not.
Head over to the Azure console, and navigate to App Services page, usually located here and try to open the website.
Mine is available here: https://raywon-web-app.azurewebsites.net
Similar workflow can be used to update the template and deploy it as well. This example is the basic version of using resource manager.
We could explore:
This will be last section of this blog post, and in here we will explore some of the tips and tricks when using CFN.
Limits:Set-AzStorageBlobContent
in PowerShell or az storage blob upload
commands in linux based terminal.You can find all the code used in this blog post here.
If you have any questions/thoughts/feedback, feel free to contact me in any platform you prefer.