GitLab CI#

GitLab CI/CD is GitLab’s in-platform pipeline engine. One .gitlab-ci.yml per repo, jobs run on operator-managed or GitLab-managed runners, the catalog of features (registry, package, security scanning, environments, review apps) is the broadest single-vendor DevSecOps surface.

Architecture#

  • Pipeline: the set of jobs triggered by an event.

  • Stage: a logical grouping of jobs that run in parallel; the next stage starts when all jobs in the current stage pass.

  • Job: a unit of work executed by one runner.

  • Runner: an agent that picks up jobs. Operator-hosted (shell, Docker, Kubernetes executor) or GitLab.com SaaS.

Pipeline shape#

# .gitlab-ci.yml
stages: [test, build, deploy]

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

test:
  stage: test
  image: node:22-alpine
  cache:
    key:   $CI_COMMIT_REF_SLUG
    paths: [.pnpm-store/]
  script:
    - corepack enable
    - pnpm install --frozen-lockfile
    - pnpm test

build:
  stage: build
  image: docker:24
  services: [docker:24-dind]
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
  script:
    - docker build -t "$IMAGE" .
    - docker push "$IMAGE"
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy:
  stage: deploy
  image: alpine:3.20
  environment:
    name: production
    url: https://app.example.com
  script:
    - apk add --no-cache curl
    - curl -X POST -H "Authorization: Bearer $DEPLOY_TOKEN" \
           -d "image=$IMAGE" https://argo.example.com/api/deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

Features that ship in the box#

Feature

Detail

Container Registry

Per-project registry; image scanning included on paid tiers.

Package Registry

npm, Maven, NuGet, PyPI, Composer, Conan, Helm.

Environments

First-class deployment targets with URL, history, and rollback buttons.

Review Apps

Ephemeral environments per MR; auto-stopped on merge / close.

Auto DevOps

Convention-over-configuration pipeline that builds, tests, scans, and deploys without a .gitlab-ci.yml.

Security scans

SAST, DAST, secret detection, dependency scanning, container scanning, license compliance (paid tiers).

Releases

First-class release objects, tag-driven, with artifacts and changelog.

Triggers#

  • Branch push, MR creation, tag push, schedule, parent-child pipelines, multi-project triggers, API trigger.

  • rules: in YAML is the modern selector. only / except are legacy; the operator uses rules going forward.

Variables and secrets#

  • CI/CD variables: per-project, per-group, per-environment. Masked variables hide in logs; protected variables only expose on protected branches / tags.

  • OIDC: GitLab can issue an OIDC token mintable into AWS / GCP / Azure short-lived credentials.

  • Vault: native integration for short-lived secret leases.

Runners#

Executor

Detail

Shell

Runs on the runner host directly. Fast, no isolation.

Docker

Each job in a fresh container. The standard default.

Kubernetes

Each job as a Pod. The right choice when GitLab runners and workloads share a cluster.

SSH

Run on a remote target via SSH. Useful for legacy hosts.

VirtualBox / Parallels / Docker Machine

Per-job VM. Higher isolation, higher cost.

When to pick GitLab CI#

  • Code already on GitLab (Self-Managed or SaaS).

  • Single-vendor DevSecOps is the goal; GitLab covers issues, MRs, CI, registries, environments, monitoring, security in one product.

  • Air-gapped or on-prem; the Self-Managed install runs anywhere Kubernetes runs.

When to pick something else#

  • Code lives in GitHub; the integration cost is not worth it.

  • Need the marketplace breadth of GitHub Actions or the build-time optimizations of Buildkite.

References#