Observation
When you start afresh with something new to learn, you tend to search online about it first, see how others are doing it and checking some best practices. At that same point, if it is Microsoft related, you will find many blogs just like this one, but also from MVP's who are subject matter experts. Now don't get me wrong, I'm not here to write and burn down some people, but I do see practices that are completely unnecessary, especially when it comes to deploying a .Bicep file to Azure via a YAML in Azure DevOps.
Take a look at this example:
stages:
- stage: Build
jobs:
- job: Build
steps:
- task: AzureCLI@2
displayName: 'build bicep artifact'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: 'az bicep build --file main.bicep'
- task: PublishBuildArtifacts@1
displayName: 'Publish artifact in pipeline'
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/main.json'
ArtifactName: 'finishedTemplate'
publishLocation: 'Container'
Here we see a .Bicep file being built/converted to a .json file, basically creating the ARM template you would use before Bicep was a thing. This is completely unnecessary when using a .Bicep file because the build step isn't required at all.
For the deployment part you will then see something like this:
stages:
- stage: deploy
jobs:
- job: deploy
steps:
- task: AzureCLI@2
displayName: 'deploy bicep template'
inputs:
azureSubscription: $(azureSubscription)
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
az group create --name $(ResourceGroupName) --location $(location)
az deployment group create `
--template-file $(Build.SourcesDirectory)/main.json `
--parameters $(Build.SourcesDirectory)/main.parameters.json `
--resource-group $(ResourceGroupName) `
--parameters resourcePrefix=$(resourceprefix)
This is just deploying the ARM template created in the Build Step. There is a lot of YAML code and the options out there for the deployment of a .Bicep file are not being utilized.
Simple Bicep deployment
So how should it be done? Well this is just one way. Maybe this is also not the best way, but at least it does utilize the .Bicep without the whole build/convert step.
stages:
- stage: Deploy
jobs:
- job: Deploy
- task: AzureCLI@2
displayName: 'Deploy Bicep'
inputs:
azureSubscription: $(azureServiceConnection)
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az group create --name $(resourceGroupName) --location $(location)
az deployment group create --resource-group $(resourceGroupName) --template-file $(templateFile)
This is it! The Azure CLI code is basically the same and I'm using an addition parameter for the filename, but the just specify the .Bicep file directly and you're good to go!
The full YAML would then be:
trigger:
- none
variables:
azureServiceConnection: 'AzureConnection'
resourceGroupName: 'rg-test'
location: 'westeurope'
templateFile: 'main.bicep'
pool:
vmImage: ubuntu-latest
stages:
- stage: Deploy
jobs:
- job: Deploy
steps:
- task: AzureCLI@2
displayName: 'Deploy Bicep'
inputs:
azureSubscription: $(azureServiceConnection)
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az group create --name $(resourceGroupName) --location $(location)
az deployment group create --resource-group $(resourceGroupName) --template-file $(templateFile)
What's next?
With multiple customers, I've seen that services are kept online 24/7, while this can easily be less, just starting the service when the use or demand is there. Let's dive into some automation with Azure Logic Apps to see how we can improve this!