Deploy Pull Requests to Kubernetes for Review with Azure DevOps
When a Pull Request got created, you might want to try out the changes in a testing environment. Here is how to optionally deploy Azure DevOps Pull Requests to a dedicated Kubernetes namespace with a single click.
To achieve automatic deployments of Pull Requests in Azure DevOps, we need a few things beside the obvious ones like a Kubernetes Cluster and your application as a Container with a Helm Chart or deployment definition.
We will setup Azure DevOps, to offer running an additional Build Validation Branch Policy whenever a Pull Request to a specific branch got opened. These build validations come as Azure Pipelines.
1name: $(BuildID)2trigger: none34# Replace these variables with your own values5variables:6 - name: AzureSubscription7 value: '<Name of Azure Resource Manager service connection>'8 - name: KubernetesConnection9 value: '<Name of Kubernetes service connection>'10 - name: ContainerRegistry11 value: '<Name of Container Registry service connection>'12 - name: Tag13 value: 'pr$(System.PullRequest.PullRequestId)-$(Build.BuildId)'1415stages:16 - stage: 'BuildPR'17 jobs:18 - job: Build19 pool:20 vmImage: 'Ubuntu-16.04'21 steps:22 # This step build the Docker image and pushes it23 # to your container registry.24 - task: Docker@225 displayName: 'Build and push container image'26 inputs:27 containerRegistry: $(ContainerRegistry)28 repository: 'test'29 command: 'buildAndPush'30 Dockerfile: 'src/Dockerfile'31 buildContext: '.'32 tags: |33 $(Tag)3435 - job: 'DeployPR'36 displayName: 'Deploy Pull Request'37 dependsOn: [Build]38 variables:39 - name: Namespace40 value: 'myapp-pr$(System.PullRequest.PullRequestId)'41 - name: ReleaseName42 value: 'myapp-pr$(System.PullRequest.PullRequestId)'4344 # This step creates a new Kubernetes Namespace45 # for the Pull Request deployment.46 - task: Kubernetes@147 displayName: 'Create Namespace'48 inputs:49 connectionType: 'Kubernetes Service Connection'50 kubernetesServiceEndpoint: $(KubernetesConnection)51 command: 'apply'52 useConfigurationFile: true53 configurationType: 'inline'54 inline: |55 apiVersion: v156 kind: Namespace57 metadata:58 name: '$(Namespace)'5960 - task: HelmInstaller@161 displayName: 'Install Helm'62 inputs:63 helmVersionToInstall: 'v3.1.0'6465 # This step deploys your application to the newly66 # created Namespace as a Helm Chart.67 - task: HelmDeploy@068 displayName: 'Install Helm chart'69 inputs:70 connectionType: 'Kubernetes Service Connection'71 kubernetesServiceConnection: $(KubernetesConnection)72 namespace: $(Namespace)73 command: 'upgrade'74 chartType: 'FilePath'75 chartPath: 'env/helm/MyApp'76 releaseName: $(ReleaseName)77 overrideValues: "\78 tag=$(Tag)"
Once the pipeline definition is written, we can create a new Azure Pipeline from it by checking the
deploy-pr.azure-pipelines.yaml file in to our repository and creating a new Azure Pipeline in Azure DevOps by selecting an existing YAML file.
Now that the pipeline is created, we can add it to the optional steps that can be kicked off from a Pull Request check.
In the Branches section of the Repos submenu in Azure DevOps, we can add Policies to each branch by clicking the menu icon next to a branch and selecting the Branch policies option.
Here we can setup requirements for Pull Request that are being made against the selected branch. Beside policies for reviewers and status checks, we can also setup Build Validations, which are Azure Pipelines that run to validate the changes. Some of them can be required and run automatically, while others can be optional and only run on a user's request. The latter is exactly what we need.
Add a Build Validation policy for the Pull Request Pipeline we created earlier and declare its trigger to manual and its requirement to optional.
Now, if someone creates a new Pull Request targeting the branch you just setup the new policy for, the reviewer can chose to deploy the changes to a dedicated Kubernetes namespace for detailed review, just by kicking off the newly created pipeline.
Running the pipeline that builds and deploys the changes is a bit hidden. In the Pull Request view, click the View all checks button to see a list of all Build Validation pipelines that can be run for this Pull Request. Here you will find the optional one, that we just created. Once you click the Queue button, your pipeline will be executed.
Personally, I like not just silently deploying a Pull Request but also posing an internal link for reviewing automatically to the Pull Request's comments. I use the Create Pull Request Comment Task from the Azure DevOps Marketplace for that but of course you need to make sure, that your Helm Chart is built in a way, that it creates a route in your Ingress Controller for the newly deployed testing version of your app.
One thing that bothers me about that solution is the fact that I have to delete the deployment manually after merging the Pull Request. Currently, there is no Trigger in Azure DevOps to run a pipeline after merging. Fingers crossed, that Azure DevOps brings a native "Deploy Pull Requests to Kubernetes" feature one day, which includes that.