Building Microservices with Azure Kubernetes Service and Azure DevOps - Part 3
Published Mar 12 2019 09:00 AM 9,509 Views
Iron Contributor

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
WORKDIR /app

# 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
WORKDIR /app
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:

Helm_02.png

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

image:
repository: aksdotnetacr.azurecr.io/aksdotnetcoder
tag: latest
pullPolicy: IfNotPresent


nameOverride: ""
fullnameOverride: ""


service:
type: ClusterIP
port: 80


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

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

 

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

AzureDevOps_CI_01.png

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.

AzureDevOps_CI_02.png

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.

AzureDevOps_CI_03.png

Figure 37 Azure DevOps Build Pipelines Step 2

 

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

AzureDevOps_CI_04.png

Figure 38 Azure DevOps Build Pipelines Step 3

 

Start by adding two Docker tasks

AzureDevOps_CI_05.png

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.*.

AzureDevOps_CI_06.png

Figure 40 Azure DevOps Build Pipelines Step 5

 

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

AzureDevOps_CI_07.png

Figure 41 Azure DevOps Build Pipelines Step 6

 

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

AzureDevOps_CI_08.png

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.

AzureDevOps_CI_09.png

Figure 43 Azure DevOps Build Pipelines Step 8

 

The first Helm task is a helm init.

AzureDevOps_CI_10.png

Figure 44 Azure DevOps Build Pipelines Step 9

 

The second Helm task is helm package.

AzureDevOps_CI_11.png

Figure 45 Azure DevOps Build Pipelines Step 10

 

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

AzureDevOps_CI_12.png

Figure 46 Azure DevOps Build Pipelines Step 11

 

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

AzureDevOps_CI_13.png

Figure 47 Azure DevOps Build Pipelines Step 12

 

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

AzureDevOps_CI_14.png

Figure 48 Azure DevOps Build Pipelines Step 13

 

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

AzureDevOps_CI_15.png

Figure 49 Azure DevOps Build Pipelines Step 14

 

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

AzureDevOps_CI_16.png

Figure 50 Azure DevOps Build Pipelines Step 15

 

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

AzureDevOps_CI_17.png

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.

AzureDevOps_CD_01.png

Figure 52 Azure DevOps Release Pipelines Step 1

 

Leave Stage 1 with the defaults.

AzureDevOps_CD_02.png

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.

AzureDevOps_CD_03.png

Figure 54 Azure DevOps Release Pipelines Step 3

 

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

AzureDevOps_CD_04.png

Figure 55 Azure DevOps Release Pipelines Step 4

 

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

AzureDevOps_CD_05.png

Figure 56 Azure DevOps Release Pipelines Step 5

 

Install the latest helm version.   

AzureDevOps_CD_06.png

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.

AzureDevOps_CD_07.png

Figure 58 Azure DevOps Release Pipelines Step 7

 

Choose Service account as authentication method.

AKS_Service_Connection_01.png

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.

AKS_Service_Connection_02.png

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.

kubectl_04.png

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.

AzureDevOps_CD_08.png

Figure 62 Azure DevOps Release Pipelines Step 11

 

Hit Save followed by Release.

AzureDevOps_CD_09.png

Figure 63 Azure DevOps Release Pipelines Step 12

 

Make sure the Version aligns with your last build.

AzureDevOps_CD_10.png

Figure 64 Azure DevOps Release Pipelines Step 13

 

The UI should indicate the progress of the deployment.

AzureDevOps_CD_11.png

Figure 65 Azure DevOps Release Pipelines Step 14

 

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

AzureDevOps_CD_12.png

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.

AzureDevOps_CD_13.png

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.

AzureDevOps_CD_14.png

Figure 68 Azure DevOps Release Pipelines Step 17

 

The output of a working CD pipeline.

 AzureDevOps_CD_15.png

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.

4 Comments
Copper Contributor

I think I'm missing something here, the pieces are not fitting in together... I don't know exactly how Helm works or what Helm Charts are, and completely new to Kubernetes. But you just configured a CI pipeline for the API Playground service... and a CD pipeline as well. After the deployment, Figure 68 shows an azuredevops-api-playground service with 9 hours age, and an akscd-helm-charts service with 2 minutes age. How come? Haven't we just deployed API Playground? 

Iron Contributor
It's entirely possible that my explanations aren't clear enough here :)
 
Helm is basically an installer tool, and helm charts are the recipes for what you install. It is also often used for deploying third-party services (illustrated in part 4).
 
So when using Azure DevOps to deploy containers you can deploy either based on the Dockerfiles/docker-compose, or you can point it to helm-charts depending on your needs. For a non-public container with no relations to other containers it might not be necessary to use Helm other than standardizing.
 
The CD pipeline used above is using the helm chart we defined earlier. The other deployment is basically a remnant from testing I did without helm that was not included in the guide. (I should have deleted it to not clutter the view.)
Copper Contributor

Thanks a lot for the clarification :)

As soon as I finish reading Part 4, I'm going for understanding Helm and its charts.

Copper Contributor

Hi Andreas,

 

First of all really nice article. Thank you for it.

 

I have some feedback on some of the issues that I have faced while setting up CI (haven't started CD yet).

 

Build of Docker image fails on Dev ops with error file not found. I fixed that by changing the working directory. Following is the updated docker file that worked on dev ops.

 

dockerfile.PNG

 

After fixing this I got another error on the same step regarding input string. I fixed that by updated my csproj file and replacing the Guid and project name with an actual guid.

 

Lastly, I got an error on helm package build 'Chart not found'. I fixed it by browsing to the helm charts folder which was under yaml rather than at the root. 

 

I hope it helps someone else. 

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