Friday 25 June 2021

Azure Resources with Bicep Using Azure Pipelines

 Bicep is the latest Azure infrastructure as code (IaC) language introduced by Microsoft. We have discussed about getting  started with Bicep in the post "Azure Infrastructure as Code (IaC) with Bicep - Getting Started with Development".  Let's look at how to implement an Azure pipeline to deploy infrastructure to Azure with Bicep in this post.

We have created a working demo of deploying an app service plan and a node Linux web app in the post "Passing Output Parameters from Bicep Modules". Let's try to deploy the same code with Azure pipeline. The code should be committed to an Azure git repo. For simplicity, the commit has been made directly to the main branch.


Note that our Bicep files are in a folder named Infra.

Next let's create a yaml pipeline file in a Pipelines/Deploy folder path.


Our main Bicep file in the post "Passing Output Parameters from Bicep Modules" requires the set of parameters shown below.


As the first step f the pipeline lets set trigger and couple of parameter values which are required for the Bicep file. The pipeline is set to execute with the latest ubuntu hosted agent. Notice how we have to supply the linuxFxVersion parameter as it is having a piping symbol. Piping symbol issue is discussed here.

trigger:
main

nameDeploy Bicep files

variables:
  
  azureServiceConnection'InfraDeploy'
  rgName'rg-biceppipeline-001' 
  rgLocation'centralus' 
  planName'plan-biceppipeline-001' 
  planSKUName'B3' 
  planSKUCapacity1
  planKind'linux'
  webappName'app-biceppipeline-001'
  linuxFxVersion'"node|16-lts"'
  templateFile'./Infra/main.bicep'

pool:
  vmImage'ubuntu-latest'

The service connection InfraDeploy is created in the team project using an SPN having contributor role to the Azure subscription.


A job to check what happens if the Bicpe script is executed can be created as follows. Notice 

stages:
stageDev
  displayNamePrecheck deploy to Dev
  jobs:
  - deploymentPrepareForDev
    environmentmyInfra-dev
    strategy:
       runOnce:
        deploy:
          steps:
          - checkoutself
          
          - taskAzureCLI@2
            displayNameSee whats gonna happen
            inputs:
              azureSubscription$(azureServiceConnection)
              scriptTypebash
              scriptLocationinlineScript
              inlineScript|
                az --version
                az deployment sub create --location $(rgLocation) \
                --template-file $(templateFile) --parameters rgName=$(rgName) \
                rgLocation=$(rgLocation) planName=$(planName) \
                planSKUName=$(planSKUName) planSKUCapacity=$(planSKUCapacity) \
                planKind=$(planKind) webappName=$(webappName) \
                linuxFxVersion=$(linuxFxVersion) --what-if

The above job allows us to see what is going happen if the Bicep script is executed. You can see three resources, resource group, app service plan and an app would be created if we execute the Bicep script. 



As you can see above we can use a manual intervention step in Azure pipeline to ensure we check and approve the changes to infra, before they are applied to the subscription. Pre validation is an important step in infra deployment specially in production scenarios to enable stable deployments of infrastructure. Manual intervention job can be added to pipeline as shown below.
  - jobwaitForValidation
    dependsOnPrepareForDev
    displayNameWait for external validation  
    poolserver    
    steps:
    - taskManualValidation@0
      inputs:
        notifyUsers'chaminda_chandrasekara@yahoo.com'
        instructions'Validate infra deploy'

Once, the manual validation is done on what happens if the Bicep script is executed, we can approve if it is doing what we intend it to do.

We can set the next job to execute the Bicep script without --what-if to apply the changes to the infrastructure. 

deploymentDeployToDev
    dependsOnwaitForValidation
    environmentmyInfra-dev
    strategy:
       runOnce:
        deploy:
          steps:
            - checkoutself
            - taskAzureCLI@2
              displayNameDeploy resources to Azure
              inputs:
                azureSubscription$(azureServiceConnection)
                scriptTypebash
                scriptLocationinlineScript
                inlineScript|
                  az --version
                  az deployment sub create --location $(rgLocation) \
                  --template-file $(templateFile) --parameters rgName=$(rgName) \
                  rgLocation=$(rgLocation) planName=$(planName) \
                  planSKUName=$(planSKUName) planSKUCapacity=$(planSKUCapacity) \
                  planKind=$(planKind) webappName=$(webappName) \
                  linuxFxVersion=$(linuxFxVersion)

When the pipeline completes we can see the resources created in Azure.



The complete pipeline code is as follows.

trigger:
main

nameDeploy Bicep files

variables:
  
  azureServiceConnection'InfraDeploy'
  rgName'rg-biceppipeline-001' 
  rgLocation'centralus' 
  planName'plan-biceppipeline-001' 
  planSKUName'B3' 
  planSKUCapacity1
  planKind'linux'
  webappName'app-biceppipeline-001'
  linuxFxVersion'"node|16-lts"'
  templateFile'./Infra/main.bicep'

pool:
  vmImage'ubuntu-latest'

stages:
stageDev
  displayNamePrecheck deploy to Dev
  jobs:
  - deploymentPrepareForDev
    environmentmyInfra-dev
    strategy:
       runOnce:
        deploy:
          steps:
          - checkoutself
          
          - taskAzureCLI@2
            displayNameSee whats gonna happen
            inputs:
              azureSubscription$(azureServiceConnection)
              scriptTypebash
              scriptLocationinlineScript
              inlineScript|
                az --version
                az deployment sub create --location $(rgLocation) \
                --template-file $(templateFile) --parameters rgName=$(rgName) \
                rgLocation=$(rgLocation) planName=$(planName) \
                planSKUName=$(planSKUName) planSKUCapacity=$(planSKUCapacity) \
                planKind=$(planKind) webappName=$(webappName) \
                linuxFxVersion=$(linuxFxVersion) --what-if

  - jobwaitForValidation
    dependsOnPrepareForDev
    displayNameWait for external validation  
    poolserver    
    steps:
    - taskManualValidation@0
      inputs:
        notifyUsers'chaminda_chandrasekara@yahoo.com'
        instructions'Validate infra deploy'

  - deploymentDeployToDev
    dependsOnwaitForValidation
    environmentmyInfra-dev
    strategy:
       runOnce:
        deploy:
          steps:
            - checkoutself
            - taskAzureCLI@2
              displayNameDeploy resources to Azure
              inputs:
                azureSubscription$(azureServiceConnection)
                scriptTypebash
                scriptLocationinlineScript
                inlineScript|
                  az --version
                  az deployment sub create --location $(rgLocation) \
                  --template-file $(templateFile) --parameters rgName=$(rgName) \
                  rgLocation=$(rgLocation) planName=$(planName) \
                  planSKUName=$(planSKUName) planSKUCapacity=$(planSKUCapacity) \
                  planKind=$(planKind) webappName=$(webappName) \
                  linuxFxVersion=$(linuxFxVersion) 


No comments:

Popular Posts