Exploring YAML based Azure Pipelines in Azure Devops
I’ve always curious of the huge variety of options on Azure DevOps & have always wanted to explore and understand the use cases for having so much features. If you are like me and you have been working with Azure DevOps over the past couple of years, you have also had some of the confusions on the below items which we will know more in this article.
The Release pipelines
In our team we have been extensively using Azure DevOps for a quite long time now, using so we have a lot of individual release pipelines that deploy the code to the cloud services like Azure Functions
or Azure Web apps.
Being in a .NET world usually any project will always have multiple API services, multiple Azure Functions that takes care of certain things in the project. Eg: If you consider a simple Hotel Management App,
there might be multiple API services like
- Admin
- Hotels
The app might also have any background jobs for processing of information at a later point of time or any recurring things that needs to be taken care of. In a Hotel Management app, we might have a background job to keep the list of items that are available on any particular hotel & update our inventory based on that.
Now the traditional way of doing this is we have a build pipeline (CI) that builds each things individually and deploys them (CD) to the cloud. Now speaking in terms of Azure
words the terms
CI
is being referred to Pipeline
and CD
means Releases
. But this is the CLASSIC
way or words. Now its just CI/CD
together in a single YAML pipeline, but MSFT does not clarify this properly.
If we do a quick Google search of Release pipelines Azure Devops
, we end up here Release Pipelines
On April 2020, MSFT released this announcement for doing CI/CD using YAML instead of doing it the classic way. Now you might wonder what’s the point of changing my existing pipelines from (Classic) to YAML, & what benefits do I get. Let’s go through the Pro’s / Con’s of it.
YAML
- It is code, and managed as a source file, so it will go through a standard code review / pull request process
- Because it is in the repo, when you need to revert the source to an early commit, the pipeline will be reverted together as well
- Comparing changes is much easier compared to the Classic UI versioning, which means it’s easier to identify root cause if build breaks
- Azure DevOps does have assistant to help building a YAML file, so it’s not as hard for first time users
- YAML Templates for resusability.
One of the biggest advantages of going over YAML is we can re-use it to build/deploy multiple things without repeating the same code over & over again. As we discussed earlier a repo might have X number of csproj
to build, but the only change in the build logic is their projectName
& the projectPath
. But if we do build the old fashioned classic pipeline, we will have to repeat the same steps like these in all the pipelines.
- Use .NETCORE CLI
- Restore Nuget
- Build
- Publish
But here in YAML, we can just build a template like this
parameters:
projectName: ''
vmImage: ''
buildConfiguration: ''
runtime: ''
stages:
- stage: 'Build'
displayName: 'Build'
pool:
name: 'Azure Pipelines'
vmImage: ${{ parameters.vmImage }}
jobs:
- job: 'Build'
steps:
- task: DotNetCoreCLI@2
displayName: 'Restore project dependencies'
inputs:
command: 'restore'
projects: |
${{ parameters.projectName }}/${{ parameters.projectName }}.csproj
- task: DotNetCoreCLI@1
displayName: 'Dotnet Build'
inputs:
command: build
projects: |
${{ parameters.projectName }}/${{ parameters.projectName }}.csproj
- task: DotNetCoreCLI@2
displayName: 'Dotnet Publish'
inputs:
command: publish
projects: |
${{ parameters.projectName }}/${{ parameters.projectName }}.csproj
publishWebProjects: true
arguments: '-c $(buildConfiguration) --runtime $(runtime) --self-contained -o $(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
And when it comes to the actual pipeline, we can just build a variables.yml
file for different projects & re-use the build template which we created earlier.
variables:
- name: projectName
value: Tailspin.SpaceGame.Web
- name: vmImage
value: ubuntu-latest
- name: buildConfiguration
value: Release
- name: runtime
value: linux-x64
- name: azureSubscription
value: AzureAppService
- name: appType
value: webAppLinux
- name: WebAppName
value: SpaceGame
- name: RuntimeStack
value: DOTNETCORE|LTS
- name: ConnectionType
value: AzureRM
The actual build pipeline only has the below code now
trigger:
- main
- releases/*
variables:
- template: webapp-variables.yml
stages:
# Build Stage
- template: template-build.yml
parameters:
projectName: $(projectName)
vmImage: $(vmImage)
buildConfiguration: $(buildConfiguration)
runtime: $(runtime)
References
- https://devblogs.microsoft.com/devops/announcing-general-availability-of-azure-pipelines-yaml-cd/
- https://docs.microsoft.com/en-us/learn/modules/create-multi-stage-pipeline/
In our next blog we will explore the Environments
section in Azure Devops. I have always seen it being empty for 3 years, I’m curious to find out what it can do to help with the Devops lifecycle.