In this short post we are going to look at automating the deployment of a Bicep template using Azure DevOps. Additionally, we are going to look at how you can convert an ARM template to Bicep.
You can find all the files used in this post on my GitHub here.
Azure Bicep is almost an abstraction of ARM (JSON) templates specifically developed for Azure and hence they are not cloud agnostic. The main difference is that Bicep is a lot more human readable and generally you need fewer lines of code to achieve the same result through the use of simple syntax.
You can read more about Bicep here
Some pre-requisites before we get started:
- Azure CLI - Download here https://learn.microsoft.com/en-us/cli/azure/install-azure-cli
- Azure DevOps Access
- Azure Subscription
Converting an ARM Template to Bicep
With the Azure CLI Microsoft provides functionality for you to decompile an ARM/JSON template to Bicep. This is extremely useful if you have existing deployments, and you want to start managing them with Bicep.
For this tutorial we are going to perform a simple resource group deployment. Let’s look at our ARM template. It’s split into a template.json
file which has the definition of what we want to deploy and a parameters.json
where we provide specific named variables required by the template.json
.
It’s worth noting that the parameters file does not need to be converted. This remains in a JSON format.
Template File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {
"rgName": {
"type": "string"
},
"rgLocation": {
"type": "string"
},
"tags": {
"type": "object",
"defaultValue": {}
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('rgLocation')]",
"name": "[parameters('rgName')]",
"properties": {},
"tags": "[parameters('tags')]"
}
],
"outputs": {}
}
Parameter File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"rgName": {
"value": "arm-template-test-rg"
},
"rgLocation": {
"value": "australiaeast"
},
"tags": {
"value": {}
}
}
}
Let’s convert our template to Bicep
1: Make sure you have the Azure CLI installed on your local machine. Navigate to the folder containing your ARM template and run the following command:
1
az bicep decompile --file template.json
Once the process completes, you will notice another file has been added to the directory called template.bicep
. This is our converted template.
2: Let’s review the code for our new bicep file:
1
2
3
4
5
6
7
8
9
10
11
12
13
targetScope = 'subscription'
param rgName string
param rgLocation string
param tags object = {
}
resource rg 'Microsoft.Resources/resourceGroups@2018-05-01' = {
location: rgLocation
name: rgName
properties: {
}
tags: tags
}
Here you can notice straight away how the template is much shorter and more concise. We went from 28 lines of code to 13. It’s worth noting that the conversion for bigger files can have some issue with naming formats so you may need to do some polishing before it’s done. We can use our existing JSON parameter file to supply the values required.
Deploy the template manually
Let’s deploy the template manually to make sure it works using the Azure CLI.
1: Run the following Azure CLI command. Make sure to replace the template and parameter file name if you used something different in the previous step.
1
2
3
4
5
az deployment sub create `
--name TestDeployment `
--location australiaeast `
--template-file template.bicep `
--parameters parameters.json
We can now see the RG is ready in the Azure portal.
Let’s delete the RG and deploy the same templates using Azure DevOps for full automation.
Deploy the template using Azure DevOps
1: Create a new pipeline from Azure DevOps by navigating to Pipelines
and then New pipelines
2: Select Azure Repos Git
for your code repository
3: Select Starter pipeline
4: Paste the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
trigger:
- master
name: Deploy Bicep files
variables:
vmImageName: 'ubuntu-latest'
azureServiceConnection: 'devops-poc3-deploy-spi'
location: 'australiaeast'
templateFile: 'bicep/azure_resource_group/template.bicep'
templateParameterFile: 'bicep/azure_resource_group/parameters.json'
pool:
vmImage: $(vmImageName)
steps:
- task: AzureResourceManagerTemplateDeployment@3
inputs:
deploymentScope: 'Subscription'
azureResourceManagerConnection: '$(azureServiceConnection)'
action: 'Create Or Update Resource Group'
location: '$(location)'
templateLocation: 'Linked artifact'
csmFile: '$(Build.SourcesDirectory)/$(templateFile)'
csmParametersFile: '$(Build.SourcesDirectory)/$(templateParameterFile)'
deploymentMode: 'Incremental'
deploymentName: 'DeployPipelineTemplate'
In this scenario I am providing the template and parameter file as a linked artifact in Azure DevOps by specifying the location in the following parameters csmFile
& csmParametersFile
. The pipeline also has a trigger for CD so every merge to the main/master branch will re-run it. Since we are using incremental deployments this is pretty safe to do.
5: Save the pipeline and run it.
We have now deployed the resource group through Azure DevOps using Bicep.
In the next post we are going to look at how to perform some automated tests on our Bicep deployment using the same pipelines including code linting, deployment validation, what-if checks and approval gates.