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


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 andif
conditional logic, making it easier to handle dynamic scenarios.
Prerequisites
Azure CLI
Bicep
Visual Studio Code with the Bicep extension
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. Thefor
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:
Subscribe to my newsletter
Read articles from Omiete directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by