Skip to content

GitLab CI/CD Cheat Sheet

Scannable patterns for the CI/CD track. Use full tutorials when you need why, not only how.

Other platforms

Jenkins and GitHub Actions come later on REBASH Academy — this sheet covers GitLab CI only.

Core concepts

Concept GitLab CI keyword / location
Pipeline config .gitlab-ci.yml (repository root)
Phase ordering stages: — jobs declare stage:
Job definition Named job with script: (required)
Conditional run rules: or workflow:rules:
DAG dependencies needs:
Job container image:
Runner selection tags: on job; runner registration tags
Secrets CI/CD variables (masked, protected, file type)
Manual gate when: manual
Matrix fan-out parallel: matrix:
Artefacts artifacts:
Cache cache:
Deploy target environment:

Pipeline anatomy

Stage Typical jobs
Validate Lint YAML, SAST config, secret detection
Test Unit, integration (fail fast)
Build Compile, Docker build, package
Scan Container, dependency, secret detection
Deploy Staging (manual), production (protected)

Quick commands and lint

Task Command / tool
CI lint (UI) Build → Pipeline editor → Validate
CI lint (API) curl --form "content=@.gitlab-ci.yml" .../ci/lint
Runner register gitlab-runner register
Runner verify gitlab-runner verify
Local YAML parse python -c "import yaml; yaml.safe_load(open('.gitlab-ci.yml'))"

Stages, jobs, and rules

stages:
  - test
  - build

unit-test:
  stage: test
  image: python:3.12-slim
  script:
    - pytest -q
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Keyword Purpose
stages: Ordered list — every stage: on a job must appear here
rules: Per-job when to create/skip (replaces legacy only/except)
workflow:rules: Whether to create a pipeline at all
when: manual Job waits for play button
allow_failure: true Job can fail without failing pipeline — use sparingly on gates

Runners and executors

Topic Notes
Shared vs self-hosted Shared = ops-free; self-hosted = data residency, GPU, cost control
Docker executor Isolated job container via image:
Kubernetes executor Pod per job; watch cluster autoscaler lag
Runner tags Job tags: must match runner tags
DinD docker:*-cli image + docker:*-dind service for image builds

Variables and secrets

Rule Detail
Never in Git Use Settings → CI/CD → Variables
Masked Values hidden in job logs when matched
Protected Available only on protected branches/tags
File type Written to temp file; path in $VAR_NAME
OIDC > long-lived keys Federated cloud roles from CI job token
Scope by environment Staging creds ≠ production creds
Rotate on leak Invalidate token; audit pipeline history

Artifacts, cache, dependencies

Pattern Pitfall
Pass build output via artifacts: Expiry too short — downstream job fails
needs: + artefacts Use dependencies: to limit which artefacts download
Cache key: $CI_COMMIT_REF_SLUG Wrong key → cold cache every run
Huge artefacts Minutes + storage cost — publish reports, not full node_modules
build:
  script:
    - make dist
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

deploy:
  needs:
    - build
  script:
    - deploy dist/

Matrix and parallelism

unit-test:
  parallel:
    matrix:
      - PYTHON: ["3.11", "3.12"]
  image: python:${PYTHON}-slim
  script:
    - pytest -q
Pattern When to use
parallel: matrix: Test fan-out across versions or OS labels
parallel: 4 Split test suite by index
needs: Skip waiting for entire stage when only one upstream job matters

Security gates

Gate When
Secret detection Every MR (secret_detection template)
SAST / dependency scan Before merge to default branch
Container scan After build, before deploy
Manual approval Staging/production promote (when: manual)
Protected environment RBAC on deploy jobs
scan-image:
  stage: scan
  needs: [build-image]
  script:
    - trivy image --exit-code 1 --severity CRITICAL "$IMAGE_TAG"

deploy-staging:
  stage: deploy
  needs: [scan-image]
  environment:
    name: staging
  when: manual
  script:
    - deploy "$IMAGE_TAG"

Environments and deploy

Keyword Purpose
environment: name Tracks deployment history per environment
environment: url Link in MR and Environments UI
environment: on_stop Job to tear down review apps
Protected environments Restrict who may deploy
resource_group: Serialise deploys to same target

Docker build in CI

variables:
  DOCKER_TLS_CERTDIR: "/certs"
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

build-image:
  image: docker:27-cli
  services:
    - docker:27-dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    - docker build -t "$IMAGE_TAG" .
    - docker push "$IMAGE_TAG"

Cost and secret landmines

Landmine Mitigation
Shared runner minutes exhaustion Cache deps; matrix only what you need; self-host heavy jobs
DinD layer cache disabled Registry cache / buildx
Unbounded matrix Cap OS × version combinations
Artefact storage growth Retention policy; don't artefact target/
Fork MR pipelines with prod secrets Restrict protected variables; use merge request pipelines carefully
:latest deploy tags Immutable SHA tags for promote
Skipping scan with allow_failure Policy waiver only with ticket

Common mistakes

  • Fixing CI by disabling tests or scan jobs
  • Wrong stage name not in top-level stages: list
  • Rebuilding image on deploy instead of promoting SHA tag
  • Production secrets available to unprotected branch pipelines
  • No CI lint in pre-merge checks
  • Confusing cache: (acceleration) with artifacts: (required handoff)