Azure devops - Arthyon/microservice-poc GitHub Wiki

We are using Azure DevOps for build and release-management.

As noted in the Overview, we have one build pipeline for each service, and one for the Kubernetes provisioning configuration.

Build

The Build configurations are specified in yml-format and checked into the repository. They are comprised of a series of pipelines, or build steps, which describes how an application should be built. In this repo the yml-files are in Infrastructure/pipelines.

There are numerous pipelines to choose from here, but we have mostly used the docker pipelines, as Docker itself is a build environment.

Our build pipeline is used to build the image using the Dockerfile, logging in to our private Azure Container Registry and pushing a new version of the image. It will also publish the OpenApi specification as a build artifact.

Since we are working in a monorepo, this must be a manual trigger as we cannot know which service was updated for each commit.

The Kubernetes-config has its own build pipeline, called provisioning. We need access to the config for each deploy, so the only job for this pipeline is to make the Helm-chart and some utility scripts available as artifacts.

Release

There is only one release pipeline. All artifacts from our build pipelines feed into that release and are used to fill the values.cloud.yaml-file with the correct data. Effectively, we are only using that file in the final stage of the deploy.

We are replacing tokens in values.cloud.yaml with environment variables in the task Replace tokens in values-file, which gets the built image names from environment-variables. Then we apply the Helm chart to the Kubernetes cluster. DevOps connects using a Service connection defined in the Azure DevOps environment. Kubernetes will figure out what parts has changed, and only deploy the relevant parts.

Defining artifacts

We must define which build artifacts that should be taken into account during the release. If a new service is introduced and updated in the Helm chart, the deploy will fail if the artifact is not defined. That is because the correct environment variable containing the image name is not present, and the variable substitution will fail.

Each input artifact in the release pipeline is added using the artifact type Build. This makes the OpenApi specification available for each service and makes it possible to set up deployment triggers that releases a new version automatically when a service is built. Then we can trigger a build of a specific service version manually to release.

Setup

Before creating pipelines and tasks, some setup is needed, namely various Service Connections and a variable group.

Variable Groups

Variable group are used to store values that you want to make available across multiple build and release pipelines. Variable groups are defined and managed in the Library tab of the Pipelines hub.

In our setup we have defined the following variables:

  • registryName: The Login server address for our Container registry.

Service connections

Go to Project settings -> Pipelines -> Service connections to register new connections. We need three connections in total.

Github connection

The service connection is named GitHub and should be created using a personal access to make it easier to revoke. This is used by the build pipelines to fetch the source code and tag commits after building, and by the release pipeline to create a github release.

Private Container Registry connection

This is realized using an Azure Resource Manager-connection. Follow the instructions to create a service principal, and scope the access to the resource group where your Azure Container Registry is located. This is used to push new images to the container registry, and by Kubernetes to pull them.

You can se how we are referencing our container registry in Infrastructure/pipelines/azure-pipeline.service.yml:

...
azureSubscriptionEndpoint: "devops-ng-service-platform"
azureContainerRegistry: "$(registryName)"
command: "login"

The azureSubscriptionEndpoint is our connection name (the 'Connection Name' you supplied when you created the Azure Resource Manager connection). The "registryName" is fetched from a linked variable group and injected during pipeline execution.

Kubernetes connection

This is of type Kubernetes and is used to run commands against Kubernetes. Follow this guide to obtain the credentials needed for Kubeconfig-authentication. In a nutshell:

  • Server URL: kubectl config view
  • Kubeconfig: %UserProfile%\.kube\config or ${HOME}/.kube/config