Building Microservices with Azure Kubernetes Service and Azure DevOps - Part 3

Published Mar 12 2019 09:00 AM 7,671 Views
Senior Member

If you missed the previous parts they can be found here: 
Building Microservices with Azure Kubernetes Service and Azure DevOps - Part 1
Building Microservices with Azure Kubernetes Service and Azure DevOps - Part 2


By now you should have a cluster running, as well as the rest of the basics. But you need a way for the code to move from your desktop to the cluster.


Creating a Continuous Integration (CI) Pipeline in Azure DevOps

One of the major points of doing microservices and containers is avoiding the “it works on my machine. While containers are a vehicle for achieving this, we also need a vehicle for carrying the container from the developer workstation to other machines. In this guide that vehicle is Azure DevOps, the artist formerly known as Visual Studio Team Services (VSTS).


DevOps as a term encompasses more than just the technical pieces, but this guide will focus only on a few isolated components. The first part is Continuous Integration (CI) which handles building of the code, and the second part is Continuous Deployment (CD) which is about deploying the code built by CI. CD will be covered in the next section.


Let’s start by creating a new Dockerfile specifically for CI. Add a new file called Dockerfile.CI with the following contents:


FROM microsoft/dotnet:2.2-sdk AS build-env

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM microsoft/dotnet:2.2-sdk
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "AKS-Web-App.dll"]


You will notice that Visual Studio arranges it as a child node under the existing Dockerfile.


We want to use Helm for packaging and deploying, and for this we need a helm chart. Create a default by executing the command below:


Figure 34 Creating a default helm chart


It is worth mentioning that there is an extension currently in preview for Visual Studio called Visual Studio Tools for Kubernetes that will automate this step for you. It is recommended to check this out, but for a deeper understanding this guide has chosen to not use this extension.


Why Helm is needed might not be clear at this point, but it adds a few extra configuration abilities. The following is a recap of the configuration files for a service:

  • Dockerfiles. These describe a single container with low-level details like base image, port openings, etc.
  • Docker-Compose. These describe a collection of containers that logically belong together. For example, having both a database container and an API container.
  • Helm charts. These typically describe additional metadata for the services, like the external url, the number of replicas, etc.

While it is not a requirement to use all three levels of configuration, it does make some things easier.


The default helm chart will actually not deploy the code you have in your VS solution, but instead an nginx container so a few adjustments will be needed. The helm charts have a templating system, but the important parts are in the values.yaml file. A simple file for this service would look like this:


# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

tag: latest
pullPolicy: IfNotPresent

nameOverride: ""
fullnameOverride: ""

type: ClusterIP
port: 80

enabled: false
annotations: {}
path: /
tls: []
# - secretName: chart-example-tls
#   hosts:
#     - chart-example.local

resources: {}
nodeSelector: {}
tolerations: []
affinity: {}


Check in your code and return to the Azure DevOps Portal.


Figure 35 Azure DevOps Build Pipelines


If you go to Pipelines => Build you will have a rather blank space, so click New pipeline to get started.


Figure 36 Azure DevOps Build Pipelines Step 1


Since the code is already checked into Azure Repos that will be the logical choice. In the next step choose Empty job as the template. There are default templates for Kubernetes, but there is a lack of visibility of what goes into them before firing it up, so this guide builds them manually by starting from scratch.


Figure 37 Azure DevOps Build Pipelines Step 2


Give the pipeline a name and select Hosted Linux as the agent pool.


Figure 38 Azure DevOps Build Pipelines Step 3


Start by adding two Docker tasks


Figure 39 Azure DevOps Build Pipelines Step 4


The first Docker task is building the image. Select the Azure subscription and the Azure Container Registry created previously. Check the boxes as seen in the image, and make sure to add $(Build.BuildID) as additional image tags. If this task looks differently for you it might be that the Docker version has defaulted to 1.* whereas this sample uses 0.*.


Figure 40 Azure DevOps Build Pipelines Step 5


The second Docker task is about pushing the image to ACR.


Figure 41 Azure DevOps Build Pipelines Step 6


Next up is adding the necessary Helm tasks. Add one installer, and two package and deploy.


Figure 42 Azure DevOps Build Pipelines Step 7


Version 2.12.3 is the latest at the time of writing, but it will automatically check each time it runs for new versions.


Figure 43 Azure DevOps Build Pipelines Step 8


The first Helm task is a helm init.


Figure 44 Azure DevOps Build Pipelines Step 9


The second Helm task is helm package.


Figure 45 Azure DevOps Build Pipelines Step 10


To wrap up the build process it is necessary to add a Publish Build Artifacts task.


Figure 46 Azure DevOps Build Pipelines Step 11


To simplify things during deploy add $(Build.BuildId) to the artifact name.


Figure 47 Azure DevOps Build Pipelines Step 12


This should make the final CI Pipeline similar to the following screenshot:


Figure 48 Azure DevOps Build Pipelines Step 13


To finish the CI process click Save & Queue to trigger a build.


Figure 49 Azure DevOps Build Pipelines Step 14


Add some comments if you like, or just click Save & Queue.


Figure 50 Azure DevOps Build Pipelines Step 15


If everything passes with flying colors it should be all green checkmarks.


Figure 51 Azure DevOps Build Pipelines Step 16


If the results are satisfactory move on to building the CD pipeline by clicking Release in the header above the output.


Creating a Continuous Deployment (CD) Pipeline in Azure DevOps

A dev might be more than happy to see the CI pipeline finish in the green, but code that compiles isn’t worth much if you’re not able to deploy it, so the next part is about building a second pipeline to take care of that.


Go to Builds => Releases and create a new pipeline. This time also choosing the Empty job template.


Figure 52 Azure DevOps Release Pipelines Step 1


Leave Stage 1 with the defaults.


Figure 53 Azure DevOps Release Pipelines Step 2


Since you started based on a build pipeline you will already have an artifact step in addition to a stage.


Figure 54 Azure DevOps Release Pipelines Step 3


Make sure that the artifacts look right and are linked to the build pipeline.


Figure 55 Azure DevOps Release Pipelines Step 4


Go to Stage 1 and add one helm installer and two helm charts.


Figure 56 Azure DevOps Release Pipelines Step 5


Install the latest helm version.   


Figure 57 Azure DevOps Release Pipelines Step 6


The first helm task is a helm init. This has a twist though. Instead of using the Azure Resource Manager connection type, (used in the CI pipeline), it is required to use a Kubernetes Service Connection. (This is due to RBAC being enabled.) This screenshot shows the result, but initially you need to click +New to create the connection.


Figure 58 Azure DevOps Release Pipelines Step 7


Choose Service account as authentication method.


Figure 59 Azure DevOps Release Pipelines Step 8


The server URL can be found by browsing to the AKS deployment in the Azure Portal and copying the API server address. Make sure to prefix with https:// when pasting it in.


Figure 60 Azure DevOps Release Pipelines Step 9


To acquire token and certificate you need to run the two kubectl commands listed:
kubectl get -n kube-system serviceaccount tiller -o yaml
kubectl get -n kube-system secret tiller-token-xyz -o yaml


The second kubectl will give you an output with two Base64-encoded strings containing the token and certificate. Copy and paste these into the form and hit OK.


Figure 61 Azure DevOps Release Pipelines Step 10


Note: the UI includes the kubectl command without the namespace (kube-system) which means you will get an error that the service account cannot be found.


You can then define the second helm task. Reuse the Kubernetes Service Connection from the previous task. Make sure you choose File path as Chart Type and that the path contains /**/*.tgz at the end.


Figure 62 Azure DevOps Release Pipelines Step 11


Hit Save followed by Release.


Figure 63 Azure DevOps Release Pipelines Step 12


Make sure the Version aligns with your last build.


Figure 64 Azure DevOps Release Pipelines Step 13


The UI should indicate the progress of the deployment.


Figure 65 Azure DevOps Release Pipelines Step 14


Let it work its magic and watch things proceed to Succeeded.


Figure 66 Azure DevOps Release Pipelines Step 15


You can click the task log and peek inside the helm upgrade log to see a kubectl output for verification.


Figure 67 Azure DevOps Release Pipelines Step 16


Jumping back to the command line you can run kubectl get all to verify things outside the Azure DevOps UI.


Figure 68 Azure DevOps Release Pipelines Step 17


The output of a working CD pipeline.


Figure 69 Azure DevOps Release Pipelines Step 18


We've come a long way, but there are a few loose threads. These will be tied up in the next, and concluding, part.

Version history
Last update:
‎Mar 11 2019 01:07 PM
Updated by: