Convert ARM Template to Bicep and Deploy with Azure DevOps - Part 1

2022, Jan 15

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

  • Visual Studio Code
  • Bicep extension for Visual Studio Code
  • Azure CLI
  • Azure PowerShell Tooling

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.

Five-Phases

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: Components

  • 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/"
      }
    }
  },
  "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: Decompile 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/')
@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

Phase 2 - Migration

Phase 3 - Refactor

Phase 4 - Test

Phase 5 - Deploy


  1. References: Migrate to Bicep