Convert ARM Template to Bicep and Deploy with Azure DevOps - Part 1
How can we convert an existing ARM Template to a Bicep Template? This is a series that will show how you can do it in steps, aligned to Microsoft guidelines.
In this first part, you will know the required tooling to do this job, which allows us to be very productive when creating bicep templates, and we are going to start exploring the Microsoft Phased Migration with an example.
Tool installation required
You will use a combination of VStudio Code + Bicep extension + (Azure CLI or Azure PowerShell).
Please check the reference for a proper installation of the tooling.
References: Install Bicep Tools
Phased Migration
Microsoft suggests a migration in 5 phases, to convert the ARM Template into Bicep Template.
The following is an example of an ARM Template that provisions a Web App in Azure. By looking at the Resources, we can identify 3 main components to be provisioned:
- Hosting Plan
- Web App
- App Insights
In this series I'll present a succinct view of what each phase means, showing the approach with the example available. The comprehensive details provided by Microsoft Docs are available as a reference1.
Phase 1 - Convert
You have the ARM Template available, either from a legacy template or from an Azure template extract.
Let's use an existing legacy ARM Template. In the solution this file is called azuredeploy.json
:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"type": "string",
"minLength": 1,
"maxLength": 3
},
"hostingPlanName": {
"type": "string",
"minLength": 3
},
"skuName": {
"type": "string",
"defaultValue": "F1",
"allowedValues": [
"F1",
"D1",
"B1",
"B2",
"B3",
"S1",
"S2",
"S3",
"P1",
"P2",
"P3",
"P4"
],
"metadata": {
"description": "Describes plan's pricing tier and capacity. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service?WT.mc_id=AZ-MVP-5005172"
}
}
},
"variables": {
"webSiteName": "[concat('sample-web-', parameters('environment'))]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]"
},
"properties": {
"name": "[parameters('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"displayName": "Website"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"properties": {
"name": "[variables('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
}
},
{
"apiVersion": "2014-04-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Insights/components",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webSiteName'))]"
],
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('webSiteName'))]": "Resource",
"displayName": "AppInsightsComponent"
},
"properties": {
"applicationId": "[variables('webSiteName')]"
}
}
]
}
and then you convert to Bicep using the Bicep decompile command:
az bicep decompile --file azuredeploy.json
After the decompilation, some warnings are displayed: In this case, only minor warnings were displayed while converting the ARM template.
Depending on your ARM Template, you may get errors that need fixing before conversion.
The new converted Bicep template is automatically generated and is called azuredeploy.bicep
. It looks like this:
@minLength(1)
@maxLength(3)
param environment string
@minLength(3)
param hostingPlanName string
@description('Describes plan\'s pricing tier and capacity. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/?WT.mc_id=AZ-MVP-5005172')
@allowed([
'F1'
'D1'
'B1'
'B2'
'B3'
'S1'
'S2'
'S3'
'P1'
'P2'
'P3'
'P4'
])
param skuName string = 'F1'
var webSiteName_var = 'sample-web-${environment}'
resource hostingPlanName_resource 'Microsoft.Web/serverfarms@2015-08-01' = {
name: hostingPlanName
location: resourceGroup().location
tags: {
displayName: 'HostingPlan'
}
sku: {
name: skuName
}
properties: {
name: hostingPlanName
}
}
resource webSiteName 'Microsoft.Web/sites@2015-08-01' = {
name: webSiteName_var
location: resourceGroup().location
tags: {
'hidden-related:${resourceGroup().id}/providers/Microsoft.Web/serverfarms/${hostingPlanName}': 'Resource'
displayName: 'Website'
}
properties: {
name: webSiteName_var
serverFarmId: hostingPlanName_resource.id
}
}
resource Microsoft_Insights_components_webSiteName 'Microsoft.Insights/components@2014-04-01' = {
name: webSiteName_var
location: resourceGroup().location
tags: {
'hidden-link:${resourceGroup().id}/providers/Microsoft.Web/sites/${webSiteName_var}': 'Resource'
displayName: 'AppInsightsComponent'
}
properties: {
applicationId: webSiteName_var
}
dependsOn: [
webSiteName
]
}
The Bicep file generated still needs some tweaks. In Phase 2 (next article) we'll take this file and create a Production-ready template.
Full Series
Phase 1 - Convert
- References: Migrate to Bicep↩