Use Bicep to Automate and Deploy Azure Virtual Machines and Associated Resources

OmieteOmiete
5 min read

If you have been using the Azure portal to set up your cloud resources, you likely have experience using Azure Resource Manager (ARM) templates for consistent build and deployment. However, there are limitations to using ARM templates which among others include: verbose and hard to read, limited support for modularity and, cryptic error message and limited validation.

Bicep

Bicep is a Domain-Specific Language (DSL) developed by Microsoft for deploying Azure resources declaritively. It is defined to simplify the process of defining and managing Infrastructure as Code (IaC) in Azure. Bicep serves as an alternative to Azure Resource Manager (ARM) templates, offering a more concise, readable, and developer-friendly syntax.

Instead of writing complex JSON files (as required by ARM templates), Bicep allows you to define Azure resources using a simpler, structured syntax. Bicep files are compiled into ARM templates during deployment, ensuring compatibility with existing Azure deployment workflows.

Key Features of Bicep

  • Declarative syntax: Bicep uses a clean, human-readable syntax that is easier to write and understand, compared to JSON-based ARM templates.

  • Modularity: Bicep supports modular design, allowing you to break down complex deployments into reusable components called modules. Modules can be shared and reused across multiple projects, improving maintainability and scalability

  • Type Safety and Validation: Bicep provides compile-time validation, catching errors before deployment. This reduces the likelihood of runtime errors during resource provisioning.

  • Support for Loops and Conditions: Bicep includes advanced programming construct like for loops and if conditional logic, making it easier to handle dynamic scenarios.

Prerequisites

Folder Structure

- main.bicep
- env/
- main.dev.parameters.json
- main.test.parameters.json
- main.prod.parameters.json
- modules/
- resource-group.bicep
- vm.bicep
- vnet.bicep

Bicep Files

The above Bicep folder contains 3 modules which includes the virtual network module, virtual machine module and the resource group module; 3 parameters.json files which includes the dev, test and prod parameters files; and the main.bicep file where the modules are called.

First we create the resource group module because we want Azure to create a Resource Group for each environment’s deployment.

It is important to create parameters for each bicep file. The target scope at the top of the file indicates to Azure that this is a subscription level deployment.

Next, we create the virtual network module.

And next, the virtual machine module. The virtual machine module has 4 resources which include the PublicIP Address resource, the Network Security Group resource, the Virtual Machine resource and the Network Interface Card resource. These resources are needed to deploy a virtual machine and they can be further modularised:

Notice the use of the for loop used in the Network Interface, PublicIP and the Virtual Machine resources. The for loop iterates over the vmInstanceCount and creates virtual machines based on the number indicated in the vmInstanceCount parameter.

And then the main.bicep file which includes parameters, variables and the modules that will be called.

Parameters are used to accept external inputs during deployment, while variables are used to define internal values or computations within the Bicep template. Parameters are customizable by the user, whereas variables are fixed and defined within the template.

Parameters are declared when you intend to change the default values at the point of deployment while variables cannot be changed.

the main.bicep file deploys a resource group, virtual network and virtual machine at the subscription level

  • the resource group is created using the resourceGroupName called from the resource-group.bicep module

  • the virtual network is scoped to the resourceGroupName and depends on it

  • the virtual machine is also scoped to the resourceGroupName and depends on the virtual network

  • virtual machines are created based on the number indicated in the vmInstanceCount

Parameter Files

You can generate parameter files for each environment from Visual Studio. Right click on the main.bicep file and click on ‘Generate Parameters File’. Then follow the prompts to either create a json parameter file or a biceparam parameter file.

This parameter file deploys 2 Windows Server virtual machines in the development environment in the Central US region.

Deployment

Now that our bicep and parameters files are ready, we can deploy to Azure using the Azure CLI.

Login to Azure on your terminal:

az login --tenant "<TenantID>" az account set --subscription "<SubscriptionID>"

Validate the Bicep file to ensure it is free of errors

az deployment sub validate --location centralus --template-file main.bicep --parameters env/main.dev.parameters.json

After validation, deploy using:

az deployment sub create --location centralus --template-file main.bicep --parameters env/main.dev.parameters.json

You will be asked to input the password for the VM on the terminal since Bicep does not store secure passwords in the parameters file. Make sure to remember your password as this will be required for redeployment and when accessing the virtual machines.

You can check the Azure portal for the resources being deployed. Go to the resource group created and click on ‘Essentials’. Under ‘Deployments’, check the status of your deployment.

You can see there are 2 virtual machines, 2 public IPs and 2 network interfaces created according to the parameters file used at the point of deployment.

Since this is a Windows Datacenter VM, you can download the RDP file. When prompted, put in the password you used at the point of deployment to access the VM.

This Bicep file can be made more efficient by further modularising the vm.bicep module and automating the deployment using CI/CD methodologies like Azure DevOps, GitHub Actions etc.

You can view the full code in my GitHub repo here.

Conclusion

This guide illustrated how to create and manage Azure virtual machines in a modular way. By structuring Bicep templates into reusable modules, you can organize and maintain your infrastructure code more effectively. This method not only improves reusability and clarity but also simplifies the management of complex deployments.

Resources

Here are some helpful resources to learn more about Bicep and Azure deployments:

0
Subscribe to my newsletter

Read articles from Omiete directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Omiete
Omiete