I'm used to using the classic Devops "Release" pipelines for deploying code changes to Kubernetes clusters. Recently I've been looking into switching to using Azure Pipelines "deployment" jobs together with "Environments". It seems to work really well and I like a lot of the features, like being able to inspect the Kubernetes entities associated with your deployments, and track the deployment history.
Something that I'm accustomed to from the classic Release pipelines is rolling back to an old deployment if it is discovered that a bug has been released (to production for example). Since Release pipelines are based on build artifacts, you simply run the deployment on the old artifact in the Releases UI.
Now using deployments under the Environments tab, I'm not sure how to run a rollback, short of actually making a code change to revert back to the old state (and run through CI builds again needlessly). Another option is, since the deployment is done relative to the code (or commit) rather than an artifact, one could manually run a new pipeline and target the given commit - but this is quite cumbersome to achieve in the Devops UI, and seems prone to errors. In my opinion rolling back should be really easy to achieve, and not prone to errors.
Any ideas how to do this? Here is a sample of my yaml file
trigger:
batch: true
branches:
include:
- master
pr:
branches:
include:
- master
variables:
azureContainerRegistry: <registryUrl>
azureContainerRegistryServiceConnection: <serviceConnection>
kubernetesConfigPath: kubernetes
kubernetesNamespace: <my-namespace>
major: 0
buildNumber: $(major).$(Build.BuildId)
imageName: "$(azureContainerRegistry)/<my-app>:$(buildNumber)"
stages:
- stage: Bake
displayName: "Build and Push image"
jobs:
- job: Validate
displayName: "Build image"
pool:
name: "Docker"
steps:
- script: docker build -t $(imageName) .
displayName: Build App
- job: Publish
displayName: "Push image"
dependsOn: Validate
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
pool:
name: "Docker"
steps:
- task: Docker@2
displayName: Login to Container Registry
inputs:
command: login
containerRegistry: $(azureContainerRegistryServiceConnection)
- script: docker push $(imageName)
displayName: PUSH $(imageName)
- stage: DeployTest
displayName: "Deploy TEST"
dependsOn: Bake
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
jobs:
- deployment: Deploy
environment: <my-test-env>.$(kubernetesNamespace)
pool:
name: "Docker"
strategy:
runOnce:
deploy:
steps:
- task: qetza.replacetokens.replacetokens-task.replacetokens@3
displayName: "Replace tokens"
inputs:
targetFiles: $(kubernetesConfigPath)/base/*.yaml
escapeType: none
tokenPrefix: "{"
tokenSuffix: "}"
- task: Kubernetes@1
displayName: "kubectl apply"
inputs:
namespace: $(kubernetesNamespace)
command: apply
arguments: -k $(kubernetesConfigPath)/test
versionSpec: 1.7.0
checkLatest: true
- task: Kubernetes@1
displayName: "kubectl rollout status"
inputs:
namespace: $(kubernetesNamespace)
command: rollout
arguments: "status deployments/<my-app>"
versionSpec: 1.7.0
checkLatest: true
- stage: DeployProd
displayName: "Deploy PROD"
dependsOn: DeployTest
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
jobs:
- deployment: Deploy
environment: <my-prod-env>.$(kubernetesNamespace)
pool:
name: "Docker"
strategy:
runOnce:
deploy:
steps:
- task: qetza.replacetokens.replacetokens-task.replacetokens@3
displayName: "Replace tokens"
inputs:
targetFiles: $(kubernetesConfigPath)/base/*.yaml
escapeType: none
tokenPrefix: "{"
tokenSuffix: "}"
- task: Kubernetes@1
displayName: "kubectl apply"
inputs:
namespace: $(kubernetesNamespace)
command: apply
arguments: -k $(kubernetesConfigPath)/prod
versionSpec: 1.7.0
checkLatest: true
- task: Kubernetes@1
displayName: "kubectl rollout status"
inputs:
namespace: $(kubernetesNamespace)
command: rollout
arguments: "status deployments/<my-app>"
versionSpec: 1.7.0
checkLatest: true