Gitlab CI/CD and Kubernetes
By: Nguyễn Đào Anh Khoa
Tags: DevOps, Kubernetes, Gitlab Ci, AWS, Infrastructure

Prerequisite

This isn’t a Kubernetes or DevOps introduction, so it’s required to have the following prerequisites:

Basic knowledge of Docker and container

Basic knowledge of Kubernetes

Bash scripting

Familiar with YAML syntax

Disclaimer

The code used in this article is for demonstration only, to provide you an abstract view of the Gitlab - Kubernetes CI/CD pipeline. I recommend that you go through the Gitlab CI/CD documentation after reading this article, and make sure you understand all the concepts there before applying this to your project.

CI/CD

The term CI/CD is used for a long time in software development. It generally stands for Continuous Integration (CI) and Continuous Delivery (CD). CI/CD bridges the gap between development team and operation team, helps the application deployment more rapidly and reliable. Nowadays, with the widespread of agile and microservices, CI/CD becomes inevitable in software development.

In this article, I’ll show you how to set up a CI/CD pipeline to test, build, deploy a Rails application using Gitlab CI/CD and Kubernetes. However, you can apply the same technique to other kinds of applications and frameworks as well.

Gitlab CI/CD

GitLab CI/CD is a tool built into GitLab. It provides an awesome set of features to build a complete CI/CD pipeline even with a community edition - at least in our use case.

The Gitlab CI/CD pipeline is split into 2 parts: Gitlab and Gitlab runner.

Gitlab creates jobs on Git/Gitlab operations such as git push, branch creation, tag creation, MR creation, …

creates jobs on Git/Gitlab operations such as git push, branch creation, tag creation, MR creation, … Gitlab runner automatically picks jobs from Gitlab and executes them.

In this article, I use Gitlab v13.5.4-ce and Gitlab runner 13.4.1 with Kubernetes executor. For more information about Gitlab runner and Kubernetes executor, please refer to the official documentation.

Setup Gitlab and Kubernetes cluster

Prepare a Kubernetes cluster.

I use an EKS cluster, but you can use other Kubernetes services of your choice.

Create namespace and a service account with an appropriate role:

kubectl apply -f k8s/gitlab-cd-role.yaml -n app-prod kubectl create sa gitlab-cd -n app-user kubectl create rolebinding gitlab-cd-role-binding —-role=gitlab-cd ---serviceaccount=app-user:gitlab-cd -n app-prod

An then get the secret and cluster CA using:

SECRET_NAME=$(kubectl get sa gitlab-cd -o jsonpath={.secrets[0].name} -n app-user) kubectl get secret $SECRET_NAME -o jsonpath={.data.token} -n app-user | base64 -d kubectl get secret $SECRET_NAME -o "jsonpath={.data['ca\.crt']}" -n app-user | base64 -d

Set Gitlab CI/CD variables:

Follow: https://docs.gitlab.com/ee/ci/variables/README.html#create-a-custom-variable-in-the-ui

Below is the list of variables that I used:

Project folder structure

The project folder should look like this:

. ├───k8s

│ ├───production

│ ├───├───deployment.yaml

│ ├───├───ingress.yaml

│ ├───├───migration-job.yaml

│ ├───├───service.yaml

│ ├───staging

├───├───├───... ├───rails

│ ├───app

│ ├───Gemfile

│ ├───... ├───Dockerfile

├───.gitlab-ci.yml

├───.gitlab-ci-test.yml

├───.gitlab-ci-build.yml

├───.gitlab-ci-staging.yml

├───.gitlab-ci-production.yml

Gitlab CI/CD pipeline

GitLab CI/CD is configured by a file called .gitlab-ci.yml placed at the repository’s root.

This file creates a pipeline, which consists of many stages such as test, build, staging … Each stage is defined under a child yml file. Each stage has one or many jobs. Each job is defined under a YAML block.

First, test the application using the ci job. This will create a pod inside the Gitlab runner cluster. Pull the project source code and run the scripts described under the script block.

Then build a base image using rebuild_base_image job. The project’s CI/CD variables can be defined in CI/CD variables setting. Here I use 2 project’s CI/CD variables which are ECR_URL and ECR_REPO.

And finally, deploy the application to either review/staging/production environment.

Result:

Depends on the configuration in your .gitlab-ci.yml file, you should get the pipelines that look like this:

Gitlab CI/CD pipeline

Pipelines for every merge requests:

Gitlab CI/CD pipeline

And the environments list: