Pipeline Basics
How Pipelines Work
PipelineTop-level container; one per commit/trigger
StageGroup of jobs that run in parallel
JobSingle task (script) within a stage
RunnerAgent that executes jobs
Triggering Pipelines
Push to branchAutomatic (default)
Merge requestVia workflow:rules or only: merge_requests
ScheduleCI/CD → Schedules in project settings
APIPOST /projects/:id/trigger/pipeline
ManualRun Pipeline button in CI/CD menu
.gitlab-ci.yml
Minimal Config
stages: [build, test, deploy] build-job: stage: build script: echo "Compiling..."
Global Keywords
stagesDefine stage order
defaultDefault values for all jobs
variablesGlobal CI/CD variables
workflowControl when pipelines are created
includeImport external YAML files
Include Templates
include: - template: Auto-DevOps.gitlab-ci.yml - local: .ci/lint.yml - project: 'group/shared-ci' file: '/templates/deploy.yml'
Jobs
Job Definition
test-unit: stage: test image: node:20 script: - npm ci - npm test
Job Keywords
scriptShell commands to run (required)
before_scriptCommands before main script
after_scriptCommands after (even on failure)
imageDocker image for the job
rulesConditions for job inclusion
needsDAG dependencies (skip stage order)
allow_failurePipeline continues if job fails
retryAuto-retry count (0-2)
timeoutMax job duration
Rules
deploy: rules: - if: '$CI_COMMIT_BRANCH == "main"' when: manual - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: never - when: on_success
Stages
Stage Order
stages: - lint - build - test - deploy
Default Stages
.preAlways runs first
buildDefault stage 1
testDefault stage 2
deployDefault stage 3
.postAlways runs last
DAG with needs
test-api: stage: test needs: ["build-api"] # skip waiting for full stage test-web: stage: test needs: ["build-web"] # runs as soon as build-web done
Variables
Defining Variables
variables: NODE_ENV: "production" DB_HOST: "postgres" job: variables: NODE_ENV: "test" # job-level override
Predefined Variables
CI_COMMIT_SHAFull commit hash
CI_COMMIT_BRANCHBranch name
CI_COMMIT_TAGTag name (if tag pipeline)
CI_PIPELINE_IDUnique pipeline ID
CI_PROJECT_DIRRepo checkout path
CI_MERGE_REQUEST_IIDMR number (MR pipelines only)
CI_REGISTRY_IMAGEContainer registry image path
Protected & Masked
ProtectedOnly available on protected branches/tags
MaskedHidden in job logs
FileWritten to a temp file; path in variable
Artifacts
Saving Artifacts
build: script: npm run build artifacts: paths: [dist/] expire_in: 1 week
Artifact Types
pathsFiles/dirs to store
excludePatterns to skip
expire_inAuto-delete after duration
reports:junitJUnit XML for MR test summary
reports:coverage_reportCobertura coverage visualization
JUnit Report
test: script: pytest --junitxml=report.xml artifacts: reports: junit: report.xml
Cache
Caching Dependencies
test: cache: key: ${CI_COMMIT_REF_SLUG} paths: [node_modules/] script: npm ci && npm test
Cache vs Artifacts
CacheSpeed up jobs; not guaranteed; same key reuse
ArtifactsPass files between jobs/stages; guaranteed
Cache Policies
pull-pushDownload + upload (default)
pullDownload only (faster for consumers)
pushUpload only (for producers)
Environments
Defining Environments
deploy-staging: stage: deploy environment: name: staging url: https://staging.example.com script: ./deploy.sh staging
Environment Features
nameEnvironment name (shown in UI)
urlLink to deployed app
on_stopJob to run when environment is stopped
auto_stop_inAuto-stop after duration
action: stopMarks job as the stop action
Review Apps
review: environment: name: review/$CI_COMMIT_REF_SLUG url: https://$CI_COMMIT_REF_SLUG.example.com on_stop: stop-review auto_stop_in: 1 week
Docker
Build & Push Image
build-image: image: docker:24 services: [docker:24-dind] script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Services (Sidecar Containers)
test: image: python:3.12 services: - postgres:16 - redis:7 variables: POSTGRES_DB: testdb POSTGRES_PASSWORD: secret
Docker-in-Docker
docker:24-dindDinD service image
DOCKER_TLS_CERTDIRSet to '/certs' or '' for TLS config
DOCKER_HOSTtcp://docker:2376 (TLS) or :2375
Common Patterns
Monorepo (changes)
test-api: rules: - changes: [api/**/*] test-web: rules: - changes: [web/**/*]
Manual Deploy Gate
deploy-prod: stage: deploy when: manual rules: - if: '$CI_COMMIT_BRANCH == "main"'
Parallel Matrix
test: parallel: matrix: - PYTHON: ["3.10", "3.11", "3.12"] DB: ["postgres", "sqlite"] script: tox -e py${PYTHON}-${DB}