Setting Up a GitLab CI/CD Pipeline for Kubernetes Deployment: A Step-by-Step Guide

S
4 min readDec 31, 2023

--

This article gives a high-level overview of integrating Kubernetes deployments to the GitLab CI/CD pipeline. As prerequisites, you will be required to have an idea of GitLab, CI/CD, and Kubernetes. At a high level, I’ll give you a brief idea.

GitLab: It is a platform designed for collaborative software development and version control, enabling teams to work together on coding, testing, and deploying applications.

CI/CD: CI/CD stands for Continuous Integration/Continuous Delivery or Continuous Deployment. It’s a method in software engineering that emphasizes frequent, automated integration of code changes into a shared repository, followed by automated testing and deployment.

Kubernetes: Kubernetes, often abbreviated as K8s, is an open-source container orchestration platform that automates many of the manual processes involved in deploying, managing, and scaling containerized applications. It groups containers that make up an application into logical units for easy management and discovery.

While we working with Kubernetes in an enterprise product, in the industry we typically manage dev, QA, and regression environments. So we have to release our code base to each of these environments using a single pipeline.

In enterprise-level applications, employing distinct environments like development, QA, regression, staging, and production is pivotal for a multitude of reasons. These include:

  • Isolation of Changes
  • Development Flexibility
  • Quality Assurance
  • User Acceptance Testing (UAT)
  • Performance Testing
  • Staging for Pre-Production
  • Safe Deployment and Rollbacks
  • Compliance and Security
  • Feedback Loops and Agile Development

Leveraging these environments streamlines the CI/CD process, allowing deployments to be managed efficiently and released to each respective environment with ease, as outlined below.

The management of various environments with Kubernetes deployments can be effectively structured as follows:

  1. Using Different Namespaces in the Same Cluster: This approach involves segmenting a single Kubernetes cluster into multiple namespaces. Each namespace acts as a virtual cluster within the larger cluster, allowing for the efficient separation of environments such as development, QA, and production.
  2. Using Different Clusters on the Same Node: Here, multiple clusters are hosted on the same physical or virtual node. This method provides an even greater level of isolation between environments, ensuring that resources and configurations are entirely separate.
  3. Utilizing Different Nodes: This strategy involves deploying each environment on separate nodes. It offers the highest level of isolation, as each environment operates on a completely independent infrastructure.

These approaches, facilitated by Kubernetes, offer flexible and robust solutions for managing diverse application environments in enterprise-level deployments.

Leveraging CI/CD, deployments to Kubernetes can be accomplished using the following methodologies:

  1. SSH to Kubernetes Cluster Node: This approach involves securely accessing a Kubernetes cluster node via SSH (Secure Shell). Once connected, deployment commands can be executed directly on the node, allowing for manual or scripted interactions with the Kubernetes system.
  2. Using the Kubernetes API: This method utilizes the Kubernetes API for deployments. It enables automated, programmatic interaction with the Kubernetes cluster, allowing CI/CD tools to seamlessly integrate and execute deployment tasks as part of the pipeline process.

These techniques provide effective ways to deploy applications to Kubernetes, each offering different levels of automation and control, suited to various CI/CD workflows.

Using the Kubernetes API

  • Create service account
# service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-ci
namespace: <namespace>
secrets:
- name: gitlab-ci-secret
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gitlab-ci-role
namespace: <namespace>
rules:
- apiGroups: ["apps"]
resources: ["pods", "deployments"]
verbs: ["get", "list", "create", "delete", "update"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gitlab-ci-role-binding
namespace: <namespace>
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gitlab-ci-role
subjects:
- kind: ServiceAccount
name: gitlab-ci
namespace: <namespace>
  • Create secret
apiVersion: v1
kind: Secret
metadata:
name: gitlab-ci-secret
annotations:
kubernetes.io/service-account.name: gitlab-ci
namespace: <namespace>
type: kubernetes.io/service-account-token
  • Using k8 API to deploy the content

The deployment template, deployment.yaml, should be added to the deployments directory at the following path: deployments/deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
name: <deployment_name>
namespace: <deployment_namespace>
spec:
replicas: 1
selector:
matchLabels:
app: <app_selector>
template:
metadata:
labels:
app: <app_label>
spec:
serviceAccountName: <service_account_name>
automountServiceAccountToken: true
containers:
- name: app
image: #IMAGE_VERSION#
ports:
- containerPort: 8080
imagePullPolicy: Always
envFrom:
- configMapRef:
name: <config_map_reference>
volumeMounts:
- name: <persistent_storage_name>
mountPath: <path_to_storage_from_pod>

Next, integrate the deployment stage into the pipeline, ensuring to substitute #IMAGE_VERSION# with the updated version of the Docker image.

sed -i -e 's|#IMAGE_VERSION#|'$I_VERSION'|g' deployments/deployment.yaml

Proceed by incorporating the following step into the pipeline:

`‘curl -k -H “Authorization: Bearer $K8S_TOKEN_REG” -H “Content-Type: application/yaml” -X PUT — data-binary “@deployments/deployment.yaml” “$K8S_API_SERVER_REG/apis/apps/v1/namespaces/<namespac>/deployments/<app_selector>”’`

The following variables should be added to the CICD variable section

  • K8S_API_SERVER_REG — https://xxx.xxx.xxx.xxx:6443
  • K8S_TOKEN_REG —Get the token by executing this command ` kubectl describe secret gitlab-ci-secret -n <namespace>`

--

--