Nowadays, automating the deployment of cloud resources has become the norm. Azure DevOps is a go-to tool known for its solidness and adaptability. In this article, we’ll dive into how to create a simple pipeline to set up Azure resources using Microsoft’s infrastructure as code language, Bicep.
Our pipeline will tackle three main tasks:
- Validate Bicep files to make sure they’re good to go.
- Run a What-If operation to preview the potential resource changes.
- And finally, deploy those resources to Azure.
If you’re looking for a quick and easy way to deploy your Azure resources, this article is for you. I’ll walk you through each step so you can understand the hows and whys. With this info, you’ll be able to tweak the process to fit your specific needs.
To begin with our Azure DevOps pipeline, make sure that you have completed the following prerequisites:
- Azure DevOps Account: You’ll need an Azure DevOps account to create and manage your pipeline.
- Azure Subscription: Ensure you have an active Azure subscription to deploy the resources.
- Service Connection in Azure DevOps: A service connection to your Azure account in Azure DevOps is needed for authentication.
Pipeline Overview #
Before diving into the finer details, it’s important to get a big-picture view of the pipeline’s entire structure. This will help you understand how everything flows from start to finish. You can find the complete pipeline code below.
trigger: branches: include: - main paths: exclude: - '*.md' - 'docs/*' variables: - group: vg_bicep_dev pool: vmImage: 'ubuntu-latest' stages: - stage: ValidateDeployment displayName: 'Validate and What-If Deployment' jobs: - job: DeployResourcesWithBicep steps: - task: AzureCLI@2 displayName: 'Validate Bicep files' inputs: azureSubscription: $(SERVICE_CONNECTION) scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group validate \ --resource-group $(RESOURCE_GROUP_NAME) \ --template-file ./your-path/template.bicep \ --parameters ./your-path/parameters.json addSpnToEnvironment: true - task: AzureCLI@2 displayName: 'What-if Bicep files' inputs: azureSubscription: $(SERVICE_CONNECTION) scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(RESOURCE_GROUP_NAME) \ --template-file ./your-path/template.bicep \ --parameters ./your-path/parameters.json addSpnToEnvironment: true - stage: DeployResources displayName: 'Create Azure resources' dependsOn: ValidateDeployment condition: succeeded() jobs: - deployment: Create displayName: 'Deployment' environment: 'deploymentEnvironment' strategy: runOnce: deploy: steps: - checkout: self - task: AzureCLI@2 displayName: 'Deploy' inputs: azureSubscription: $(SERVICE_CONNECTION) scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group create \ --resource-group $(RESOURCE_GROUP_NAME) \ --template-file ./your-path/template.bicep \ --parameters ./your-path/parameters.json addSpnToEnvironment: true
The pipeline has two main stages. The first stage is to validate Bicep files to ensure there are no issues during deployment. The second stage is the actual deployment of Azure resources if validation passes. In the following sections, we will analyze each component of this pipeline and explain its purpose and function in detail.
Pipeline Breakdown #
In this section, we will explore the fundamental elements that comprise an Azure DevOps pipeline configuration file.
A trigger is a set of conditions that dictate when the pipeline should automatically run.
trigger: branches: include: - main paths: exclude: - '*.md' - 'docs/*'
The pipeline triggers on changes to the main branch, while excluding Markdown files and any files in the docs folder.
Variables in a pipeline are key-value pairs that can be used to pass information and control behavior throughout the pipeline.
variables: - group: vg_bicep_dev
A variable group named vg_bicep_dev is referenced, which can be used throughout the pipeline.
Agents or runners are computing resources where the pipeline jobs will be executed.
pool: vmImage: 'ubuntu-latest'
The pipeline jobs will run on a VM with the latest Ubuntu image.
Validation Stage #
This stage is crucial for ensuring that the Bicep configurations are accurate and won’t cause issues during deployment. It performs a validation check and a “what-if” analysis to preview the changes without making any actual changes.
- stage: ValidateDeployment displayName: 'Validate and What-If Deployment' ...
Deployment Stage #
This stage is responsible for the actual deployment of Azure resources based on the Bicep template and its associated parameters. The dependsOn: ApproveDeployment attribute ensures that this deployment stage waits for the ApproveDeployment validation stage to complete before it begins. Moreover, the condition: succeeded() attribute ensures that the deployment will only proceed if the preceding ApproveDeployment stage was successful, adding an extra layer of security and robustness to the deployment process.
- stage: DeployResources displayName: 'Create Azure resources' dependsOn: ValidateDeployment condition: succeeded() ...
Building Your CI/CD Pipeline #
1- Create YAML File: Using the built-in Azure DevOps editor or a code editor like VS Code, create a new YAML file for your pipeline.Once the file is created, paste or write the pipeline code into this YAML file.Save the file, adhering to naming conventions and best practices for the file name, such as AzureDevOps_BicepDeployment_Simple.yaml.
2- Directory Structure: If you’re using a code editor, ensure you save this YAML file in a well-organized directory structure, ideally within a root directory named pipelines in your cloned repository.
3- Uploading the YAML File to Azure DevOps:
- Navigate to your Azure DevOps project.
- Go to the Pipelines section and select “New pipeline.”
- Follow the prompts, and when asked, choose the option to use an existing YAML file.
- Browse and select the AzureDevOps_BicepDeployment_Simple.yaml file you saved earlier.
4- Executing the Pipeline:
- Once the pipeline is created, it will appear in the list of pipelines within your project.
- Select the pipeline and click on “Run” to execute it.
- Azure DevOps will now process the YAML file, and the pipeline will trigger based on the conditions defined in the trigger section of the YAML file.
Recommendation: For effective organization and easier navigation, it is recommended to store your pipeline YAML files within a dedicated directory structure in your repository. A commonly used approach is to create a root directory named pipelines and place all pipeline-related YAML files inside it.
Common Issues and Troubleshooting #
Deploying Azure resources through a pipeline can still be challenging, even with careful planning. It is common to face unexpected issues. Here, I will discuss common problems and their solutions.
Pipeline Not Triggering #
- Symptom: Despite making changes to branches other than main, the pipeline doesn’t start.
- Solution: Ensure that the YAML file is correctly placed in your repository and that the branch policies don’t prevent the pipeline from triggering. Also, verify the trigger configuration in your YAML.
Bicep Validation Errors #
- Symptom: The ValidateDeployment stage fails during the Bicep file validation.
- Solution: Check the error logs for specific details. Common issues include incorrect resource specifications, syntax errors in the Bicep file, or missing parameters in the JSON file.
Missing Service Connection #
- Symptom: Azure tasks fail with authentication or permission errors.
- Solution: Ensure that the $(SERVICE_CONNECTION) variable is correctly set and that the associated service connection in Azure DevOps has the necessary permissions on the target Azure subscription.
Resource Deployment Failures #
- Symptom: The DeployResources stage fails even if the validation was successful.
- Solution: While validation can catch syntactic and some logical issues, it might not account for all runtime problems. Ensure that the Azure subscription has the required quota, check resource dependencies, and ensure no conflicts with existing resources.
References and useful links #
Thank you for taking the time to read my post. I sincerely hope that you find it helpful.