How to Deploy to Kubernetes using a Gitlab CI Pipeline

Automatically deploy new revisions of your app to your Kubernetes cluster with the push of a button!

(Update 6.5.2022): Gitlab now has shared their own instructions for running a Kubernetes command from a Gitlab CI job. Their approach differs slightly from the one outlined here. The approach in this article still works, but I want to make it clear that my approach isn’t the only way to solve this problem.

If you are not familiar with Kubernetes, I hope that this article can give you a deeper understanding of the power of Kubernetes. Regardless of your skill level, I hope that reading this article inspires you iterate on your infrastructure process.

This article assumes that you already have a Kubernetes cluster with a working Kubeconfig for a user that has permissions to access the cluster. It also assumes that Gitlab’s servers can access your cluster. We will cover these topics, including how to implement Kubernetes Role-Based Access Control in a future article. Let’s get started:

Prepare and download your Kubeconfig

The Kubeconfig is a file that grants access to your Kubernetes cluster. The user that the Kubeconfig describes should have permission to update the deployments in your cluster.

Upload your Kubeconfig to Gitlab

The first step is to provide Gitlab with your Kubeconfig.

Navigate to your project or group CI/CD Settings:

Variables can be configured both at the Group and Project levels

Click Expand on the Variables section:

and then, click the Add Variable button to reveal the following dialog:

The key MUST be KUBECONFIG

Make sure that the Type of the variable is set to File.

Then, copy the contents of your Kubeconfig into the Value input box and finally, click the Add Variable button.

Create the Deploy Step

Once you’ve added your Kubeconfig as a CI pipeline variable, you’re ready to update your .gitlab-ci.yml with a new deploy stage. Below is an example:

deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: [""]
  when: manual
  script:
    - kubectl set image deployment/my-deployment my-deployment=my.registry.com/my-image/$CI_COMMIT_REF_SLUG

Let’s explore a few parts of this pipeline step:

image

This definition uses bitnami’s kubectl docker image. I do not want to maintain my own kubectl docker image, and bitnami’s kubectl image is the most reputable one I’ve found in my research. The info page on bitnami’s image is here: https://bitnami.com/stack/kubectl/containers

By default, the image will run kubectl, which will create unnecessary noise in our pipeline log. Thankfully, gitlab lets us override this behavior by specifying the entrypoint as an empty set [""]. This way, no command will be run when the image is run.

when

This definition uses when: manual, which will pause the pipeline when it reaches the deploy step. Normally, the pipeline step would automatically execute, but with the when keyword, Gitlab will show a clickable play button that will start the job:

You may want to remove the when: manual declaration when creating a pipeline to deploy to a test or staging server.

script

The script section of the pipeline step is where the image switch is performed – we call the kubectl command and set the image of a deployment named my-deployment to my.registry.com/my-image/$CI_COMMIT_REF_SLUG. These values should be changed to reflect your build process.

The deployment name, specified in deployment/my-deployment, references the metadata.name property of your Kubernetes deployment. The image set command, which also uses the name my-deployment, references a different value, spec.template.spec.initContainers[].name, or spec.template.spec.containers[].name.

Bonus: Change Multiple Images in One Command

You may have noticed that the set command above only contains the name of one image to change, and also that a Kubernetes deployment definition is allowed to have multiple images, specified through containers or initContainers. The kubectl command supports setting multiple images in one command by separating the images to be set by a space. I find this approach to be more clear and efficient than running multiple commands in the pipeline stage:

kubectl set image deployment/my-deployment my-deployment=my.registry.com/my-image/$CI_COMMIT_REF_SLUG my-other-deployment=my.registry.com/my-other-image/$CI_COMMIT_REF_SLUG

That’s it! Your Gitlab CI Pipelne should now be equipped with a new button that lets you deploy new revisions of your app! 🥳

Further Reading:

Kubernetes Deployments https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

Using Kubeconfig Files https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/

Gitlab .gitlab-ci.yml documentation https://docs.gitlab.com/ee/ci/yaml/

updated 6.05.2022

Infrastructure / Architecture, Software Engineering