Deploying to Kubernetes with GitLab CI/CD

35 minLesson 4 of 4

Learning Objectives

  • Connect GitLab to a Kubernetes cluster
  • Deploy applications using Helm from CI/CD pipelines
  • Manage dev, staging, and production environments
  • Implement manual production deployments
  • Use environment stop actions for cleanup

Connecting GitLab to Kubernetes

Using KubeConfig

Store your cluster config as a CI/CD variable:

  1. Get your kubeconfig: cat ~/.kube/config
  2. In GitLab: Settings → CI/CD → Variables
  3. Add variable:
    • Key: KUBE_CONFIG
    • Value: contents of ~/.kube/config
    • Type: File

Using in Pipeline

deploy:
  script:
    - mkdir -p ~/.kube
    - cat $KUBE_CONFIG > ~/.kube/config
    - export KUBECONFIG=~/.kube/config
    - kubectl get nodes
    - kubectl apply -f manifests/

Multi-Environment Deployment

Namespace Setup

kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace prod

Pipeline with Environments

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  NODEPORT_DEV: 30000
  NODEPORT_STAGING: 30001
  NODEPORT_PROD: 30002
 
stages:
  - test
  - build
  - deploy_dev
  - deploy_staging
  - deploy_prod
 
test:
  stage: test
  image: python:3.11
  script:
    - pip install -r requirements.txt
    - pytest
 
build:
  stage: build
  script:
    - docker build -t $IMAGE .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $IMAGE
 
deploy_dev:
  stage: deploy_dev
  environment:
    name: development
    url: http://$SERVER_IP:$NODEPORT_DEV
  script:
    - mkdir -p ~/.kube
    - cat $KUBE_CONFIG > ~/.kube/config
    - helm upgrade --install app ./chart/
      --namespace dev
      --set image.repository=$CI_REGISTRY_IMAGE
      --set image.tag=$CI_COMMIT_SHORT_SHA
      --set service.nodeport=$NODEPORT_DEV
 
deploy_staging:
  stage: deploy_staging
  environment:
    name: staging
    url: http://$SERVER_IP:$NODEPORT_STAGING
  script:
    - mkdir -p ~/.kube
    - cat $KUBE_CONFIG > ~/.kube/config
    - helm upgrade --install app ./chart/
      --namespace staging
      --set image.repository=$CI_REGISTRY_IMAGE
      --set image.tag=$CI_COMMIT_SHORT_SHA
      --set service.nodeport=$NODEPORT_STAGING
 
deploy_prod:
  stage: deploy_prod
  environment:
    name: production
    url: http://$SERVER_IP:$NODEPORT_PROD
  when: manual
  only:
    - main
  script:
    - mkdir -p ~/.kube
    - cat $KUBE_CONFIG > ~/.kube/config
    - helm upgrade --install app ./chart/
      --namespace prod
      --set image.repository=$CI_REGISTRY_IMAGE
      --set image.tag=$CI_COMMIT_SHORT_SHA
      --set service.nodeport=$NODEPORT_PROD

Helm Chart Structure

chart/
├── Chart.yaml
├── values.yaml
└── templates/
    ├── deployment.yaml
    └── service.yaml

values.yaml

replicaCount: 1
image:
  repository: nginx
  pullPolicy: Always
  tag: "latest"
imagePullSecrets:
  - name: regcred
service:
  type: NodePort
  port: 80
  nodeport: 30000

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      imagePullSecrets:
        {{- toYaml .Values.imagePullSecrets | nindent 8 }}
      containers:
        - name: app
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          ports:
            - containerPort: 80

Registry Authentication in Kubernetes

Create a secret for pulling private images:

kubectl create secret generic regcred \
  --from-file=.dockerconfigjson=$HOME/.docker/config.json \
  --type=kubernetes.io/dockerconfigjson \
  -n dev
 
# Repeat for staging and prod namespaces

Environment Stop Actions

Clean up environments when branches are deleted:

deploy_dev:
  environment:
    name: dev/$CI_COMMIT_REF_NAME
    on_stop: stop_dev
 
stop_dev:
  stage: deploy_dev
  when: manual
  environment:
    name: dev/$CI_COMMIT_REF_NAME
    action: stop
  script:
    - helm uninstall app -n dev

GitLab Environments Dashboard

After deployment, view environments in Operate → Environments:

  • See which version is deployed where
  • Click Open to visit the application
  • Click Stop to tear down an environment
  • View deployment history

Summary

  • Store kubeconfig as a CI/CD File variable for cluster access
  • Use Helm charts for templated Kubernetes deployments
  • --set overrides values per environment (dev/staging/prod)
  • when: manual requires human approval for production
  • environment: tracks deployments in GitLab's dashboard
  • on_stop: enables environment cleanup
  • Create registry secrets in each namespace for private image pulls

Module Complete

You now have a complete GitLab CI/CD skillset:

  1. CI/CD concepts and GitLab architecture
  2. Writing .gitlab-ci.yml pipelines
  3. Runners and container registries
  4. Kubernetes deployments with Helm

These skills enable you to automate the entire path from code commit to production deployment.