2
votes

So I am deploying a web application on the Azure app service with azure YAML pipelines.

The way I am doing this is that I have created 2 YAML pipelines, one for build and the other for release where I have multi-stage for different environments. for ex; Dev, Test, and Prod.

The reason I have divided it into two pipelines is that my build pipeline produces build artifacts and by using the Resouces section on my release pipeline I can select the previously generated build(from the UI) and deploy it to whatever stage I want to. The idea is that I don't want to build every single time when I need deployment to one of those stages. I should be able to use the previously produced artifacts as well as the old build artifact version. Below is my release pipeline and how I am using the Resources section.

Release Pipeline

trigger:
- none

resources:
  pipelines:
  - pipeline: myappbuild  
    source: build-test # name of the pipeline that produces an artifact
    trigger: 
      branches:
      - master

pool:
  vmImage: 'windows-latest'

stages: 
- stage: 'DeployToDev'
  jobs:
  - deployment: Deploy 
    displayName: Deploy
    environment: dev 
    pool: 
      vmImage: 'windows-latest'
    strategy: 
      runOnce: 
        deploy:
          steps:          
          - download: myappbuild
            artifact: drop  
          - task: AzureRmWebAppDeployment@4
            displayName: 'Deploy Azure App Service'
            inputs:
              packageForLinux: '$(System.DefaultWorkingDirectory)/**/*.zip'
              AppSettings: '-ASPNETCORE_ENVIRONMENT $(EnvironmentName) -ReleaseName $(Release.ReleaseName) -BuildId $(Build.BuildId)'

This is running fine. I am able to pick the previous build from the UI and can deploy that build to whatever stage I have in my release pipeline.

Questions:

  1. In the release pipeline it's difficult to say what is currently deployed on what stages. I want to be able to tell what is in each environment based on what's been run. so In my case, I have 3 env and I want to be able to tell which run was for which env. since the Classic UI pipeline has a concept of release where it shows which artifact is currently deployed where in just 1 screen. wherein YAML you only get to see 3 green dots for each environment I have under the Runs section which doesn't tell what is currently deployed on the Dev stage.

  2. Can I achieve this within one pipeline, rather than creating 2 pipelines? Can I have just 1 pipeline having my build and release? I know it's possible to have a multi-stage where I can have one stage for build and others for my release. but then how am I able to pick the previous build to deploy to whatever stage. since I am not sure if I can use the resources section in this use case. Idea is that I don't want to run build all the time. if this is something achievable can someone please direct me to correct the document?

Thank you.

2

2 Answers

0
votes

I'd combine the build and deploy stages together, something like this:

stages:
- stage: Build
  jobs:
  - job: Build
    steps:
    - task: YourBuildTask1
      inputs:
        YourInputsHere: ...
    - task: Etc
      inputs:
        Etc: ...
    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: ...
        ArtifactName: 'drop'
        publishLocation: 'Container'
- stage: DEV
  dependsOn: Build
  jobs:
    - deployment: Deployment
      variables:
        - template: myDevVariables.template.yml
      environment: DEV
      strategy:
        runOnce:
          deploy:
            steps:     
            - task: AzureRmWebAppDeployment@4
              displayName: 'Deploy Azure App Service'
              inputs:
                packageForLinux: '$(Pipeline.Workspace)/**/*.zip'
                AppSettings: '-ASPNETCORE_ENVIRONMENT $(EnvironmentName) -ReleaseName $(Release.ReleaseName) -BuildId $(Build.BuildId)'
- stage: Test
  dependsOn: DEV
  jobs:
    - deployment: Deployment
      variables:
        - template: myTestVariables.template.yml
      environment: Test
      strategy:
        runOnce:
          deploy:
            steps:     
            - task: AzureRmWebAppDeployment@4
              displayName: 'Deploy Azure App Service'
              inputs:
                packageForLinux: '$(Pipeline.Workspace)/**/*.zip'
                AppSettings: '-ASPNETCORE_ENVIRONMENT $(EnvironmentName) -ReleaseName $(Release.ReleaseName) -BuildId $(Build.BuildId)'

Obviously not debugged, but I'm doing something similar here in my own pipelines successfully. You make the first deployment stage dependent on the build, each subsequent environment dependent on the previous. You add approval gates for each environment to add manual intervention and prevent the build from just deploying everywhere at once.

Note, in this example, I've substituted $(Pipeline.Workspace) for $(System.DefaultWorkingDirectory), as I've found frequently with YAML pipelines that $(System.DefaultWorkingDirectory) has a different value for different job types.

In the example below, if I didn't like the result of the 20200105.1 deployment, I could click on the 20201218.1 run below it, and choose a new environment to deploy to.

Example Run List

0
votes

I would combine them as that is where the value really is. Keeping them separate just leads to move overhead and maintenance. If worried about a CI/CD YAML can support that via a single pipeline with a condition wrapped around the deployments stages to check the branch using - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master')}} :

For question on environment visibility click the "Environment" button in Azure DevOps as it will show all the jobs that have hit that environment across all the repos within the project.

Best practice would be to create a CD for each commit into master. This would create a release for all environments and deploy to DEV. Thus keeping a release for every build.