Special Offer: My C#/.NET Bootcamp Course is out now. Get 10% OFF using the code FRIENDS10.

We will create an ARM Template to create an Azure Web App and use the Azure CLI to run the ARM Template to create the resources on the Microsoft Azure cloud platform.

ARM Templates

ARM stands for Azure Resource Manager. It’s a Microsoft technology that allows us to define templates for Azure cloud resources.

We can use ARM Templates as an automated alternative to manually creating and configuring the resources using the Azure Portal. If you want to learn more about the concept of Infrastructure as Code and available tooling, read the Introduction to Infrastructure as Code first.

We can define the template a single time and execute it as many times as we need it. It will always create the resources with the same configuration.

We can use different ways to create and execute those ARM Templates. We can use Powershell, the Azure CLI, and run the template inside the Azure Portal.

Installing the Azure Resource Manager (ARM) Tools for Visual Studio Code

We will use Visual Studio Code to create ARM templates and the Azure CLI to execute the templates.

The Azure Resource Manager (ARM) Tools extension provides Schema integration, code snippets, and other features that help us write the ARM template files.

Let’s install the Visual Studio Code extension first. Next, we create a new file and name it web-app.json.

The Azure Resource Manager (ARM) Tools extension provides us with code snippets. We use the arm! (exclamation mark) code snippet to generate an outline of an ARM Template that is scoped to an Azure Resource Group.

The Structure of an ARM Template

An ARM Template consists of a JSON document following a schema. Let’s quickly go through the different root properties.

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

The schema property contains an URL to the latest ARM Template schema. This schema defines that our ARM Template is scoped to an Azure Resource Group. We usually keep this value as is.

The contentVersion property allows us to version our templates. When using Git, this property isn’t that important, and I usually don’t update it.

The parameters property allows us to define parameters that we can use inside the template and populate when executing the ARM Template. For example, when we want to provide a URL of a web app, parameters are handy.

The function property allows us to declare functions that we can use within our ARM template. It allows for advanced solutions, and we don’t use it in this video.

The variables property allows us to define dynamic values based on parameters or other values.

The resources property is the most important property. Here, we will define the Azure resources that we want to create.

The output property allows us to define values that are shown in the output when executing the ARM Template. 

Defining a Web App Resource

When we add a curly brace within the resources property to define a JSON object, the Visual Studio Code extension provides additional code snippets. 

Let’s use the arm-web-app code snippet to add a section to the JSON file.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "functions": [],
    "variables": {},
    "resources": [
    {
        "name": "webApp1",
        "type": "Microsoft.Web/sites",
        "apiVersion": "2020-12-01",
        "location": "[resourceGroup().location]",
        "tags": {
            "[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/appServicePlan1')]": "Resource",
            "displayName": "webApp1"
        },
        "dependsOn": [
            "[resourceId('Microsoft.Web/serverfarms', 'appServicePlan1')]"
        ],
        "properties": {
            "name": "webApp1",
            "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'appServicePlan1')]"
        }
    }
    ],
    "outputs": {}
}

The type property defines the service we want to create. We can set the name of the resource to whatever we want. However, it needs to be globally unique. Let’s name the web app arm-webapp-demo.

The apiVersion property is very important. It describes what API version we want to use when creating a service. Azure is a constantly evolving cloud platform, and if there is a new version of a service, the apiVersion protects our template from breaking. Always use the latest available API version when creating a new ARM Template.

The location property defines in what Azure Region the resource will be created. We can reference functions within square brackets. We use the location of the current resource group.

Resource tagging is optional. Therefore, we remove this section of the template.

The dependsOn property is important. It defines that this resource will be created after the referenced resources. Otherwise, all resources are created in parallel.

An Azure Web App runs on an App Service plan. In this snippet, we reference an existing App Service Plan.

However, we will change that later because we will create our App Service Plan within the ARM template.

The properties we explored so far are available for many resources. Resource-specific properties are placed in the properties property. For a web app, we only have two required properties. 

The name and the serverFarmId properties. We use the same name as previously defined. The serverFarmId needs to reference the App Service Plan, which we will create next.

Defining an App Service Plan

We use the arm-plan code snippet to generate the resource section to define an App Service Plan.

We set the name to arm-web-app-plan. Again, we remove the tags section of the template and set the name within the properties section a second time.

The Sku property defines the pricing level of the App Service Plan. F1 specifies the free plan.

Keep in mind that you can only have a single free App Service Plan per Azure Region.

Now, let’s update the references to the App Service Plan in the Web App section and reference the App Service Plan we just defined.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "functions": [],
    "variables": {},
    "resources": [
        {
            "name": "arm-web-app-plan",
            "type": "Microsoft.Web/serverfarms",
            "apiVersion": "2020-12-01",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "F1",
                "capacity": 1
            },
            "properties": {
                "name": "arm-web-app-plan"
            }
        },
        {
            "name": "arm-webapp-demo",
            "type": "Microsoft.Web/sites",
            "apiVersion": "2020-12-01",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[resourceId('Microsoft.Web/serverfarms', 'arm-web-app-plan')]"
            ],
            "properties": {
                "name": "arm-webapp-demo",
                "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', 'arm-web-app-plan')]"
            }
        }
    ],
    "outputs": {}
}

That’s it for the template definition.

Installing & Authenticating the Azure CLI

We want to use the Azure CLI to run the ARM Template we just created. Make sure you have the Azure CLI installed. 

You can check it using the az command in a terminal of your choice.

If you haven’t installed it, make sure to do it right now. I use Winget to install the Azure CLI on my Windows computer using PowerShell. It takes a few minutes to download and install.

winget install -e --id Microsoft.AzureCLI

After the installation has been completed, make sure to open another terminal. Otherwise, the az command won’t work. I open a Bash terminal inside Visual Studio Code, and, as you can see, the az command is now available. With az version we get the current version of the Azure CLI.

Next, we need to connect to our Azure account. We can use the az login command and log into our account using the browser.

Deploying the ARM Template using the Azure CLI

Next, we can use the following command to execute the ARM template. 

az deployment group create --resource-group arm-templates --template-file ./web-app.json

As we learned before, an ARM template has a specific scope. 

When we scope an ARM Template to the resource group scope, we cannot create a resource group itself. In this case, we would need a second template targeting the subscription scope.

To simplify this demo, we go to the Azure Portal and manually create the resource group.

Back in Visual Studio Code, we run the command again.

It takes a few seconds to create the resources. If there are no errors, a JSON with additional information will be returned when the operation has been completed.

Let’s go back into the Azure Portal and press the Refresh button.

Azure Portal: Created Resources

As you can see, the new resources appear. We have an App Service Plan named arm-web-app-plan and a Web App named arm-webapp-demo.

Conclusion

There is a lot more you can do using ARM Templates. For example, as hinted at the beginning of the video, we can use parameters to make the templates more reusable.

However, the goal here was to get up to speed with what ARM Templates are, create your first ARM Template, and create the resources using the Azure CLI.

In future videos of this series, we will look at different Infrastructure as Code tools, including Bicep, the next evolution of ARM Templates providing an even better developer experience.

Consider subscribing to my YouTube channel to learn more about Infrastructure as Code and .NET development.

 

Claudio Bernasconi

I'm an enthusiastic Software Engineer with a passion for teaching .NET development on YouTube, writing articles about my journey on my blog, and making people smile.