Getting Started with Azure Bicep and GitHub Actions

In this post I’m going to demonstrate how to use Azure “bicep” together with Github actions for pipeline based infrastructure deployments using the new bicep language.

BICEP

Project “Bicep” is a new project from Microsoft for declarative, template based IaC (Infrastructure as Code). It’s basically a language wrapper for ARM templates. ARM templates are widely used but at the mean time, they’re also kind of “hard to learn”, especially for beginners. As bicep is not a custom IaC provider such as Terraform or Pullumi are, the unerlying architecture of ARM (Azure Resource Manager) is not touched or changed. Bicep mainly consist of the two following components:

  • Visual Studio Code Extention (language interpreter)
  • Compiler (converts .bicep files into native .json arm templates)

WHY BICEP

When we have a closer look under the hood, Terraformers will notice, that Microsoft took a lot of the good things of HCL (Hashi Corp Language) over to bicep. The language is way more simpler and readable than json, and provides functionalities we always asked for when using native ARM templates.

The following example shows a virtual network with two subnets:

param vnetName string
param addressPrefixes array
param subnet1Name string
param subnet2Name string
param subnet1AddressPrefix string
param subnet2AddressPrefix string
param location string = '${resourceGroup().location}'

resource vnet 'Microsoft.Network/virtualNetworks@2020-06-01' = {
  location: location
  name: vnetName
  properties:{
    addressSpace:{
      addressPrefixes:addressPrefixes 
    }
    subnets:[
      {
        name:subnet1Name
        properties:{
          addressPrefix: subnet1AddressPrefix          
        }
      }
      {
        name:subnet2Name
        properties:{
          addressPrefix: subnet2AddressPrefix          
        }
      }
    ]    
  }
}

While for beginners, the code still may look complicated, bicep shows it’s real power in the details. Just to mention a few of them:

  • dependencies are automatically resolved
  • variables can be references by just typing their names
  • concat is not required any more, instead strings can be combined with interpolated variables or parameters
  • Referenced resources or modules are automatically compiled as child or nested resources

Disclaimer: Project “bicep” is still in public preview and you should not use it for critical production deployments. But to mention, it’s quite stable already and a lot of core functionalities are implemented already.

GITHUB ACTIONS

As a lot of you might have noticed already, Microsoft is pushing Github a lot since the acquisition back in 2018. Github Actions are the version of Azure DevOps Pipelines. Configured as YAML code files, the are very similar to Azure DevOps or Gitlab pipelines, although syntax and functionalities differ a bit between the platforms.

Example:

name: AzureDeploy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      # Log into Azure
      - uses: azure/login@v1
        with:
          creds: $

      # Deploy ARM Template
      - name: Deploy Azure Resource Manager (ARM) Template
        uses: Azure/arm-deploy@v1
        with:
          scope: subscription
          region: westeurope
          subscriptionId: 7487a514-51f9-4050-9bb1-79de33af929d
          template: ./201-VirtualNetworksWithPeering/main.json     

DEMO CASE

In this demo scenario I will demonstrate the following use case:

  • Use bicep modules to achieve a modular template structured approach
  • Create two virtual networks including peering using a master template with referenced modules
  • Use Github Actions for CI/CD

(1) INSTALLING NIGTHLY BICEP BUILDS

Nightly Bicep Builds

(2) CREATING BICEP MODULES

If you want to start with the basics I recommend the following read. Getting Started with Bicep

For now we will have a look at modules. A module is nothing more than a single .bicep file (template) which can be references in a main template later. So let’s create the first component template, a virtual network with two subnets.

param vnetName string
param addressPrefixes array
param subnet1Name string
param subnet2Name string
param subnet1AddressPrefix string
param subnet2AddressPrefix string
param location string = '${resourceGroup().location}'

resource vnet 'Microsoft.Network/virtualNetworks@2020-06-01' = {
  location: location
  name: vnetName
  properties:{
    addressSpace:{
      addressPrefixes:addressPrefixes 
    }
    subnets:[
      {
        name:subnet1Name
        properties:{
          addressPrefix: subnet1AddressPrefix          
        }
      }
      {
        name:subnet2Name
        properties:{
          addressPrefix: subnet2AddressPrefix          
        }
      }
    ]    
  }
}

–> Save the file as virtualNetwork.bicep

As a second module we create a template for vNet peering.

param localVnetName string
param remoteVnetName string
param remoteVnetRg string

resource peer 'microsoft.network/virtualNetworks/virtualNetworkPeerings@2020-05-01' = {
  name: '${localVnetName}/peering-to-remote-vnet'
  properties: {
    allowVirtualNetworkAccess: true
    allowForwardedTraffic: true
    allowGatewayTransit: false
    useRemoteGateways: false
    remoteVirtualNetwork: {
      id: resourceId(remoteVnetRg, 'Microsoft.Network/virtualNetworks', remoteVnetName)
    }
  }
}

(3) REFERENCING BICEP MODULES IN MAIN TEMPLATE

Now let’s create the main file in which we are going to reference the modules. Modules are referenced using the “module” prefix followed by the relatove path to the module, the component .bicep file. Additionally, the following examples contains some other specialities covered.

  • Creation of two resource groups
  • Multi-RG deployment
  • Custom Dependencies for Peering
targetScope = 'subscription'

param rg1Name string
param rg1Location string = 'westeurope'
param rg2Name string
param rg2Location string = 'westeurope'
param vnet1Name string
param vnet2Name string

resource rg1 'Microsoft.Resources/resourceGroups@2020-06-01' = {
  name: '${rg1Name}'
  location: '${rg1Location}'
} 

resource rg2 'Microsoft.Resources/resourceGroups@2020-06-01' = {
  name: '${rg2Name}'
  location: '${rg2Location}'
} 


module vnet1 '../101-resourcelibrary/virtualNetwork2Subnets.bicep' = {
  name: 'vnet1'
  scope: resourceGroup(rg1.name)
  params:{
    vnetName: vnet1Name
    addressPrefixes:[
    '10.0.0.0/8'
    ]
    subnet1Name:'d-sne${vnet1Name}-01'
    subnet2Name:'d-sne${vnet1Name}-02'
    subnet1AddressPrefix: '10.1.1.0/24'
    subnet2AddressPrefix: '10.1.2.0/24'
  }
}

module vne2 '../101-resourcelibrary/virtualNetwork2Subnets.bicep' = {
  name: 'vnet2'
  scope: resourceGroup(rg2.name)
  params:{
    vnetName: vnet2Name
    addressPrefixes: [
      '172.16.0.0/16'
    ]
    subnet1Name:'d-sne${vnet2Name}-01'
    subnet2Name:'d-sne${vnet2Name}-02'
    subnet1AddressPrefix: '172.16.1.0/24'
    subnet2AddressPrefix: '172.16.2.0/24'
  }
}

module peering1 '../101-resourcelibrary/vnetPeering.bicep' = {
  name: 'peering1'
  scope: resourceGroup(rg1.name)
  dependsOn:[
    vnet1
    vne2
  ]
  params:{
    localVnetName:vnet1Name
    remoteVnetName: vnet2Name
    remoteVnetRg: rg2Name
  }
}

module peering2 '../101-resourcelibrary/vnetPeering.bicep' = {
  name: 'peering2'
  scope: resourceGroup(rg2.name)
  dependsOn: [
    vne2
    vnet1
  ]
  params:{
    localVnetName:vnet2Name
    remoteVnetName: vnet1Name
    remoteVnetRg: rg1Name
  }
}

(4) COMPILE BICEP MAIN FILE

Compiling the main bicep together with all referenced modules is as easy as follows:

bicep compile .\main.json

This command validates the syntax and creates a resulting, single, json ARM template.

(5) DEPLOY THE COMPILED JSON FILE

Deploying the compiled json is nothing different that using native ARM templates.

New-AzDeployment -Name "vnetDemo" -location westeurope -TemplateFile .\main.json -rg1Name d-rgr-corenet-01 -vnet1Name d-vne-core-01 -rg2Name d-rgr-spokenet-01 -vnet2Name d-vne-spoke-01

You can also use Azure CLI of course instead of PowerShell. Additionally you might want to use the -whatif parameter first, so you can evaluate the predicted results, before really deploying the template.

(6) CREATING THE GITHUB ACTION WORKFLOW

The last step is to create a CI/CD Pipeline for our bicep demo environment. The workflow will contain two main jobs:

  • build (bicep compile)
  • deploy (deploying the compiled ARM template)

First we need to create a service principal with contributor permissions on the target subscription:

az ad sp create-for-rbac --name GithubBicepDemo --role contributor --scopes /subscriptions/{your subscription-id} --sdk-auth

We need to note the following parameters of the output:

Getting Started with Azure Bicep and GitHub Actions

Ok, next, we’re going to add the credentials as a github protected credential object:

Getting Started with Azure Bicep and GitHub Actions

The last step is to create the Github Actions Workflow, in fact the CI/CD pipeline. You can use this example as your general workflow template for bicep based ARM deployments.

name: AzureDeploy
env:
  subscriptionId: '<your subscription ID goes here>'
  bicepFile: './201-VirtualNetworksWithPeering/main.bicep'
  armtemplateFile: './201-VirtualNetworksWithPeering/main.json'

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
     
      - name: Bicep Build
        uses: aliencube/bicep-build-actions@v0.1
        with:
          files: '$'
      
      #create artifact tar
      - name: 'Tar files'
        run: tar -cvf bicep-artifacts.tar ./

      #upload artifacts
      - name: Upload Artifacts
        uses: actions/upload-artifact@v2
        with:
          name: bicep-artifacts
          path: bicep-artifacts.tar
      
  deploy:
    runs-on: ubuntu-latest
    needs: build

    steps:
      # download & exract build artifacts
      - uses: actions/download-artifact@v2
        with:
          name: bicep-artifacts
      
      # Extract files from build tar
      - name: 'Extraxt Files'
        run: tar -xvf bicep-artifacts.tar
      
      # Login to Azure
      - uses: azure/login@v1
        with:
          creds: $

      # Deploy compiled ARM Template
      - name: Deploy Azure Resource Manager (ARM) Template
        uses: Azure/arm-deploy@v1
        with:
          scope: subscription
          region: westeurope
          subscriptionId: $
          template: '$'

DECOMPILING EXISTING ARM TEMPLATES

What if you already have a complementary libary of ARM templates and you wanted to have them as templates in bicep style?

Option 1: (decompile using bicep CLI)

bicep decompile .\yourARMTemplate.json

Option 2: (Use Bicep Playgound) https://bicepdemo.z22.web.core.windows.net/

CONCLUSION

In this post I showed how to use bicep based templates including a modular approach by leveraging modules. Also I included a complete example how to automatically build/deploy a bicep solution using Github Actions (Workflows). All the examples are available on my Github Account. https://github.com/drmiru/bicepdemo

Find more great content here!

USEFUL RESOURCES

Get started with Bicep: https://github.com/azure/bicep

Get started with ARM deployments using Github Actions: https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deploy-github-actions

About the Author:

Michael Rueefli is one of the ‘scopewyse’ founders. As an experienced solutions architect he is supporting customers and partners in training, concepts, designs and implementations using cloud solutions from Microsoft Azure Microsoft Azure and Microsoft 365. As a long-standing Microsoft MVP, he supports communities worldwide with his Microsoft Azure and Data Center know-how. He is a regular speaker at international events and conferences. He also shares his knowledge on his private blog: www.miru.ch

Reference:

Rueefli, M. (2020). Getting Started with Azure Bicep and GitHub Actions. Available at: https://www.miru.ch/get-started-bicep-with-github/ [Accessed: 20th January 2020].

Share this on...

Rate this Post:

Share:

Topics:

Azure

Tags: