Integrate GitLab with Kubernetes for automated deployments using CI/CD pipelines and runners

Advanced 45 min Apr 20, 2026 97 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up GitLab CI/CD pipelines with Kubernetes runners for automated application deployments. Configure RBAC, implement rolling updates, and establish production-grade deployment strategies.

Prerequisites

  • Kubernetes cluster with admin access
  • GitLab instance or GitLab.com account
  • Docker registry access
  • kubectl and helm installed

What this solves

GitLab CI/CD integration with Kubernetes automates your application deployments, eliminating manual deployment steps and reducing human error. This setup enables automated testing, building, and deployment of applications directly to Kubernetes clusters using GitLab runners with proper RBAC controls and deployment strategies.

Step-by-step configuration

Install and configure GitLab Runner

Install GitLab Runner on your system to handle CI/CD jobs with Kubernetes executor support.

curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
sudo dnf install gitlab-runner

Install kubectl and helm

Install Kubernetes command-line tools needed for cluster management and application deployment.

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update && sudo apt install helm
sudo dnf install helm

Create GitLab service account and RBAC

Set up proper Kubernetes RBAC permissions for GitLab Runner to deploy applications securely.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-runner
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: gitlab-runner
rules:
  • apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets"] verbs: ["get", "list", "create", "update", "delete"]
  • apiGroups: ["apps"]
resources: ["deployments", "replicasets"] verbs: ["get", "list", "create", "update", "delete"]
  • apiGroups: [""]
resources: ["pods/log"] verbs: ["get", "list"]
  • apiGroups: [""]
resources: ["pods/exec"] verbs: ["create"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gitlab-runner roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: gitlab-runner subjects:
  • kind: ServiceAccount
name: gitlab-runner namespace: default
kubectl apply -f /home/gitlab-runner/gitlab-service-account.yaml

Get service account token

Extract the service account token needed for GitLab Runner authentication with the Kubernetes cluster.

kubectl create secret generic gitlab-runner-token --from-literal=token=$(kubectl create token gitlab-runner --duration=8760h)
kubectl get secret gitlab-runner-token -o jsonpath='{.data.token}' | base64 -d > /tmp/gitlab-token

Register GitLab Runner with Kubernetes executor

Register the runner with your GitLab instance using Kubernetes executor for containerized builds and deployments.

sudo gitlab-runner register \
  --url "https://gitlab.example.com/" \
  --registration-token "YOUR_REGISTRATION_TOKEN" \
  --executor "kubernetes" \
  --description "kubernetes-runner" \
  --kubernetes-host "https://YOUR_KUBERNETES_API_SERVER:6443" \
  --kubernetes-ca-file "/etc/kubernetes/pki/ca.crt" \
  --kubernetes-token-file "/tmp/gitlab-token" \
  --kubernetes-namespace "default" \
  --kubernetes-service-account "gitlab-runner" \
  --kubernetes-image "ubuntu:22.04" \
  --kubernetes-cpu-request "100m" \
  --kubernetes-memory-request "128Mi" \
  --kubernetes-cpu-limit "1000m" \
  --kubernetes-memory-limit "1Gi"
Note: Replace YOUR_REGISTRATION_TOKEN with the token from your GitLab project's CI/CD settings, and YOUR_KUBERNETES_API_SERVER with your cluster's API server address.

Configure GitLab Runner Kubernetes settings

Fine-tune the runner configuration for optimal performance and security in Kubernetes environments.

concurrent = 4
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "kubernetes-runner"
  url = "https://gitlab.example.com/"
  token = "YOUR_RUNNER_TOKEN"
  executor = "kubernetes"
  [runners.kubernetes]
    host = "https://YOUR_KUBERNETES_API_SERVER:6443"
    ca_file = "/etc/kubernetes/pki/ca.crt"
    token_file = "/tmp/gitlab-token"
    namespace = "default"
    service_account = "gitlab-runner"
    image = "ubuntu:22.04"
    cpu_request = "100m"
    cpu_limit = "1000m"
    memory_request = "128Mi"
    memory_limit = "1Gi"
    pull_policy = "if-not-present"
    [runners.kubernetes.node_selector]
      kubernetes.io/os = "linux"
    [runners.kubernetes.pod_security_context]
      run_as_non_root = true
      run_as_user = 1000
      fs_group = 2000

Create deployment namespace and resources

Set up a dedicated namespace for your application deployments with proper resource quotas.

apiVersion: v1
kind: Namespace
metadata:
  name: myapp-production
  labels:
    environment: production
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: app-quota
  namespace: myapp-production
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "10"
    services: "5"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: app-limits
  namespace: myapp-production
spec:
  limits:
  - default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    type: Container
kubectl apply -f /home/gitlab-runner/app-namespace.yaml

Create application deployment template

Set up a Kubernetes deployment template for your application with rolling update strategy.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp-production
  labels:
    app: myapp
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        version: "__VERSION__"
    spec:
      serviceAccountName: gitlab-runner
      containers:
      - name: myapp
        image: "__IMAGE__"
        ports:
        - containerPort: 8080
        env:
        - name: ENV
          value: "production"
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: myapp-production
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

Configure GitLab CI/CD pipeline

Create a comprehensive CI/CD pipeline that builds, tests, and deploys your application to Kubernetes.

stages:
  - build
  - test
  - deploy

variables:
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_CERTDIR: "/certs"
  KUBERNETES_NAMESPACE: myapp-production
  APP_NAME: myapp

build:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  before_script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  only:
    - main
    - develop

test:
  stage: test
  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  script:
    - echo "Running application tests"
    - npm test
  only:
    - main
    - develop

deploy_staging:
  stage: deploy
  image: alpine/k8s:1.28.2
  before_script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --certificate-authority="$KUBE_CA_PEM_FILE"
    - kubectl config set-credentials gitlab --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=gitlab
    - kubectl config use-context default
  script:
    - sed -i "s|__IMAGE__|$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA|g" k8s/deployment.yaml
    - sed -i "s|__VERSION__|$CI_COMMIT_SHORT_SHA|g" k8s/deployment.yaml
    - kubectl apply -f k8s/deployment.yaml
    - kubectl rollout status deployment/$APP_NAME -n $KUBERNETES_NAMESPACE --timeout=300s
    - kubectl get pods -n $KUBERNETES_NAMESPACE -l app=$APP_NAME
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy_production:
  stage: deploy
  image: alpine/k8s:1.28.2
  before_script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --certificate-authority="$KUBE_CA_PEM_FILE"
    - kubectl config set-credentials gitlab --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=gitlab
    - kubectl config use-context default
  script:
    - sed -i "s|__IMAGE__|$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA|g" k8s/deployment.yaml
    - sed -i "s|__VERSION__|$CI_COMMIT_SHORT_SHA|g" k8s/deployment.yaml
    - kubectl apply -f k8s/deployment.yaml
    - kubectl rollout status deployment/$APP_NAME -n $KUBERNETES_NAMESPACE --timeout=300s
    - kubectl get pods -n $KUBERNETES_NAMESPACE -l app=$APP_NAME
  environment:
    name: production
    url: https://example.com
  when: manual
  only:
    - main

Set up GitLab CI/CD variables

Configure environment variables in GitLab for secure cluster access and deployment configuration.

kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.server}'
kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ca.crt
cat /tmp/gitlab-token
Note: Add these values as CI/CD variables in your GitLab project: KUBE_URL (server URL), KUBE_CA_PEM_FILE (base64 encoded CA certificate), and KUBE_TOKEN (service account token).

Configure advanced deployment strategies

Implement blue-green deployment strategy for zero-downtime deployments with automatic rollback capabilities.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp-rollout
  namespace: myapp-production
spec:
  replicas: 5
  strategy:
    blueGreen:
      activeService: myapp-active
      previewService: myapp-preview
      autoPromotionEnabled: false
      scaleDownDelaySeconds: 30
      prePromotionAnalysis:
        templates:
        - templateName: success-rate
        args:
        - name: service-name
          value: myapp-preview
      postPromotionAnalysis:
        templates:
        - templateName: success-rate
        args:
        - name: service-name
          value: myapp-active
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: "__IMAGE__"
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-active
  namespace: myapp-production
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-preview
  namespace: myapp-production
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080

Install ArgoCD for advanced GitOps

Deploy ArgoCD for GitOps-based deployment management with automated sync and rollback capabilities.

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Wait for ArgoCD to be ready

kubectl wait --for=condition=available --timeout=300s deployment/argocd-server -n argocd

Get initial admin password

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Configure monitoring and alerts

Set up monitoring for your deployments with Prometheus metrics and Grafana dashboards.

apiVersion: v1
kind: ServiceMonitor
metadata:
  name: myapp-monitor
  namespace: myapp-production
  labels:
    app: myapp
spec:
  selector:
    matchLabels:
      app: myapp
  endpoints:
  - port: metrics
    path: /metrics
    interval: 30s
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: myapp-alerts
  namespace: myapp-production
spec:
  groups:
  - name: myapp.rules
    rules:
    - alert: MyAppDown
      expr: up{job="myapp"} == 0
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "MyApp is down"
        description: "MyApp has been down for more than 1 minute"
    - alert: MyAppHighErrorRate
      expr: rate(http_requests_total{job="myapp",code=~"5.."}[5m]) > 0.1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "High error rate in MyApp"
        description: "Error rate is above 10% for 5 minutes"
kubectl apply -f k8s/monitoring.yaml

Verify your setup

Test the complete CI/CD pipeline and verify deployments are working correctly.

# Check GitLab Runner status
sudo gitlab-runner status

Verify Kubernetes connectivity

kubectl get nodes kubectl get serviceaccount gitlab-runner -o yaml

Check namespace and resources

kubectl get all -n myapp-production kubectl describe deployment myapp -n myapp-production

Monitor deployment rollout

kubectl rollout status deployment/myapp -n myapp-production kubectl get pods -n myapp-production -l app=myapp

Check service connectivity

kubectl get svc -n myapp-production kubectl port-forward svc/myapp-service 8080:80 -n myapp-production

Common issues

Symptom Cause Fix
Runner registration fails Invalid registration token or GitLab URL Verify token in GitLab CI/CD settings and check URL accessibility
Kubernetes authentication error Service account token expired or invalid Recreate service account token: kubectl create token gitlab-runner --duration=8760h
Pod creation fails Insufficient RBAC permissions Check ClusterRole permissions and verify service account binding
Image pull fails Registry authentication or network issues Verify CI_REGISTRY_PASSWORD variable and network connectivity
Deployment timeout Resource constraints or health check failures Check pod logs: kubectl logs -l app=myapp -n myapp-production
Service not accessible Label selector mismatch Verify service selector matches deployment labels

Next steps

Running this in production?

Want this handled for you? Running this at scale adds a second layer of work: capacity planning, failover drills, cost control, and on-call. Our managed platform covers monitoring, backups and 24/7 response by default.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.