Continuous Delivery

What is Continuous Delivery(CD)

The first paragraph from continuousdelivery.com

Continuous Delivery is the ability to get changes of all types—including new features, configuration changes, bug fixes and experiments—into production, or into the hands of users, safely and quickly in a sustainable way.

Why do CD

Top three reasons:

  • Lower risk of changes - By delivering smaller changes to production and exercising the deployment process many times a day, we significantly lower the risk of quality regression or unexpected deployment hurdles.

  • Faster time-to-market - We often have emergency applications that need to get deployed in production under quite tight deadlines. Having a safe delivery pipeline makes this possible.

  • Higher quality - by running our ever-growing regression test suites after every change in the code, we make sure we do not take a step backwards quality-wise.

Process overview

Continuous Integration(CI)

CI is an integral part of the CD. It ensures the quality of the code and packages the assets, making them ready for deployment.

We trigger the CI process for all GitHub Pull Requests targeting the main branch without publishing assets. We trigger the CI process and publish the assets when making changes to main and release/** branches.

We lint the code, check the formatting of the code, perform Node modules vulnerability scan, run the unit and integration tests, run the end-to-end tests (results recorded to cypress.io: https://dashboard.cypress.io/projects/4q7jz8/) and finally, if successful, we package the code and assets. You can find a sample script to run the process for an app of your choosing here. To find out more about the thinking around the CI process, please see the ADR.

Code and assets from island.is are packaged in Docker containers and stored in a private Docker registry hosted in AWS ECR. The ECR is configured to perform vulnerability scanning of all Docker images pushed to it.

When the CI process finishes successfully and has published assets, we trigger the Delivery pipeline to the Dev environment.

Merge queues

Kodiaq (our merge bot) applies first-come-first-served policy to all PRs. To merge code to main, developers add the automerge label to their PRs and Kodiaq will take care of the rest. Developers do not have privileges to merge/push manually to the main branch to prevent accidents from happening and maintain fairness, since merging manually to main would bypass the Kodiak merge queue.

Configuration

Our deployment platform is Kubernetes and our applications' deployment and configuration is specified using Helm. Additionally, we have the configuration for our infrastructure in AWS specified using Terraform. These two configuration sources are hosted in two separate git repositories with restricted access.

Delivery pipeline

We use Spinnaker as a deployment tool for Kubernetes. We have a few application pipelines that are identical for the most part.

Each application has a pipeline per deployment environment. The pipeline prepares (aka bakes) the configuration for the concrete environment, waits for manual approval of the deployment and then performs the deployment with the freshly baked configuration.

The pipelines are defined and versioned in our Helm repo. The input to the pipelines is as follows:

  • a Docker image tag - specifies which revision of the code/assets to be deployed.

  • a Helm config tag - specifies which revision of the configuration to be deployed.

The Helm chart stored in our Chartmuseum comes in as an asset as well as value files containing environmental specific values. Docker tag, value files and helm chart are baked together creating Kubernetes manifest, that can be deployed to a specific environment.

The CI process triggers the pipelines upon a successful build, which automatically deploys to our Dev environment. After manual approval, it is possible to deploy to Staging and then Prod as well.

Our Spinnaker is accessible here. Note that to be able to log in, your membership to the island-is github organization must be set to public. You can change that here.

Last updated