GitLab CI
All GitLab CI config lives in .gitlab-ci.yml at the repo root. Use stages to sequence jobs, rules: to control when jobs run, environments: for deployment tracking, and protected variables for secrets. Register a self-managed runner on your node for builds that need cluster network access.
Basic Pipeline Structure
A minimal pipeline with test, build, and deploy stages — covers the most common CI flow. Jobs in the same stage run in parallel; stages run sequentially.
stages:
- test
- build
- deploy
variables:
IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
default:
image: docker:24
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
test:
stage: test
image: python:3.12
script:
- pip install -r requirements.txt
- pytest tests/ -v --tb=short
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
build:
stage: build
script:
- docker build -t $IMAGE .
- docker push $IMAGE
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
deploy-staging:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: staging
url: https://staging.myapp.example.com
script:
- kubectl set image deployment/myapp myapp=$IMAGE -n staging
- kubectl rollout status deployment/myapp -n staging --timeout=5m
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'Docker Build with GitLab Registry
Use $CI_REGISTRY_IMAGE to push images to the project's built-in GitLab container registry. Tag with both the commit SHA (for traceability) and a mutable tag like latest.
build-image:
stage: build
image: docker:24
services:
- docker:24-dind
variables:
CACHE_IMAGE: "$CI_REGISTRY_IMAGE:cache"
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
# Pull cache layer to speed up builds
- docker pull $CACHE_IMAGE || true
- docker build
--cache-from $CACHE_IMAGE
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
--tag $CI_REGISTRY_IMAGE:latest
--build-arg BUILDKIT_INLINE_CACHE=1
.
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CACHE_IMAGE
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'Kubernetes Deploy Job
Store the kubeconfig as a GitLab CI/CD file variable (base64-encoded). The deploy job decodes it and runs kubectl or helm. Use environment: to track deployments in GitLab's Environments UI.
deploy-production:
stage: deploy
image: dtzar/helm-kubectl:3.14
environment:
name: production
url: https://myapp.example.com
variables:
NAMESPACE: production
before_script:
# KUBECONFIG is a CI/CD file variable containing the base64-encoded kubeconfig
- echo "$KUBECONFIG_B64" | base64 -d > /tmp/kube.conf
- export KUBECONFIG=/tmp/kube.conf
- kubectl cluster-info
script:
- helm upgrade --install myapp ./charts/myapp
--namespace $NAMESPACE
--set image.repository=$CI_REGISTRY_IMAGE
--set image.tag=$CI_COMMIT_SHORT_SHA
--wait --timeout 5m
after_script:
- rm -f /tmp/kube.conf
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
when: manual # require manual approval for production
environment:
name: production
action: startGitLab Runner Setup
For builds that need access to cluster internals or private networks, register a self-managed runner on a node inside the cluster. The kubernetes executor runs each job as a Pod, avoiding static infrastructure.
# Install GitLab Runner on Kubernetes using Helm
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm upgrade --install gitlab-runner gitlab/gitlab-runner \
--namespace gitlab \
--create-namespace \
--set gitlabUrl=https://gitlab.example.com \
--set runnerToken="$GITLAB_RUNNER_TOKEN" \
--set rbac.create=true \
--set executor=kubernetes
# Check runner is connected
kubectl get pods -n gitlab
kubectl logs -n gitlab -l app=gitlab-runner -f
# Register a shell runner on a VM (alternative)
gitlab-runner register \
--non-interactive \
--url "https://gitlab.example.com/" \
--registration-token "$REGISTRATION_TOKEN" \
--executor "shell" \
--description "my-shell-runner" \
--tag-list "shell,deploy"Useful Predefined Variables
| Variable | Value |
|---|---|
$CI_COMMIT_SHORT_SHA | 8-char commit SHA |
$CI_COMMIT_TAG | Git tag (empty if no tag) |
$CI_COMMIT_BRANCH | Branch name |
$CI_DEFAULT_BRANCH | Project default branch (e.g. main) |
$CI_REGISTRY_IMAGE | GitLab registry path for this project |
$CI_REGISTRY_USER | Auto-generated registry username |
$CI_REGISTRY_PASSWORD | Auto-generated registry password |
$CI_PIPELINE_SOURCE | push / merge_request_event / schedule / … |
$CI_ENVIRONMENT_NAME | Name of the current environment |