Skip to main contentSkip to user menuSkip to navigation

GitLab CI/CD

Master GitLab CI/CD: pipeline configuration, runners, DevOps workflows, and automation.

30 min readIntermediate
Not Started
Loading...

What is GitLab CI/CD?

GitLab CI/CD is a pipeline system that turns repository events into controlled, repeatable jobs. A project stores its pipeline policy in .gitlab-ci.yml. GitLab creates the pipeline and coordinates job state; one or more runners provide the machines or containers that execute those jobs.

That separation matters. GitLab can decide that a production deployment is allowed, but the runner still receives the code, credentials, network access, and operating system privileges needed to execute it. Pipeline correctness therefore depends on both the job graph and the execution boundary.

Core invariant

A job should run only when its required inputs are complete, on a runner whose trust level matches the code and credentials the job can access.

One execution

Pipeline

A set of jobs created for a push, merge request, tag, schedule, API call, or another configured source.

Unit of work

Job

A script plus its image, variables, dependencies, retry policy, timeout, artifacts, environment, and runner tags.

Execution boundary

Runner

An agent that claims eligible jobs and executes them through a shell, container, Kubernetes pod, or another supported executor.

Pipeline evidence

Artifact

A job output such as a package, test report, or scan report that later jobs and people can retrieve under an explicit retention policy.

Schedule work from dependencies, not stage labels

Stages are broad ordering barriers. By default, jobs in one stage can run in parallel, but the next stage waits for the previous stage to succeed. The needs keyword adds specific job dependencies, so an independent path can move forward without waiting for unrelated jobs in an earlier stage.

Use the lab to compare both models under a finite runner-slot limit. The schedule is a deterministic teaching model: durations are supplied inputs, jobs never fail or retry, and runner startup, artifact transfer, and GitLab scheduling overhead are excluded.

Pipeline scheduling lab

Resolve the dependency graph

Loading fixed jobs, durations, stages, and needs edges.

Loading scheduling model...

Two bottlenecks can look similar in the pipeline graph:

  • Barrier delay: a ready job waits for unrelated work because stage ordering is broader than the true dependency.
  • Runner queueing: a ready job waits because every eligible runner slot is busy.
  • Critical-path work: a job waits because an input it genuinely needs is still running; adding runners cannot remove that dependency.

GitLab's current needs documentation explains how dependency-based scheduling bypasses stage order and how optional jobs or artifact downloads change the contract.

Treat artifacts and caches as different contracts

Both features move files, but they answer different questions.

Correctness input

Artifacts carry results

Use artifacts for build outputs, reports, and evidence produced by a job. Declare which later jobs need them, restrict access when necessary, and set a retention period that matches audit and rollback requirements.

Optional acceleration

Caches avoid repeated work

Use a cache for reproducible dependencies that can be fetched or rebuilt again. Key it from a lockfile or another stable input, and never make pipeline correctness depend on a cache hit.

When a job declares needs, it downloads artifacts only from the needed jobs unless that transfer is disabled. Keep the graph and the data contract aligned: a job that consumes dist/ should name the job that produced dist/.

The official artifacts guide and cache guide document the current transfer and retention behavior.

Decide which pipelines should exist before selecting jobs

Pipeline-level workflow: rules decides whether GitLab creates a pipeline. Job-level rules then decides whether a job is present and can also set attributes such as when or allow_failure. Mixing broad final rules with push and merge-request cases can create duplicate pipelines for the same change.

Start from explicit sources:

  • create a merge-request pipeline when review feedback is needed;
  • create a default-branch pipeline for integration and delivery;
  • create a tag pipeline only when a tag represents a release contract;
  • reject every source that has no named purpose;
  • make a dependency optional when rules can legitimately omit the producer job.

This example creates one intended pipeline per source, starts source-only checks immediately, keys the dependency cache from the lockfile, and passes an immutable build output through needs.

A dependency-aware application pipeline

Validate merged configuration in GitLab's pipeline editor and exercise push, merge request, tag, schedule, and manual cases. The current workflow reference describes when its rules are evaluated.

Make the runner trust boundary explicit

A runner executes repository-controlled code. That makes runner selection a security decision, not merely a capacity decision. Tags express capability matching; the Protected setting limits a runner to protected branches and tags, with separately configured merge-request behavior. Neither mechanism is a sandbox by itself.

Select a workload and a runner pool. The lab evaluates a small, explicit policy model: tag matching, protected-ref eligibility, workspace lifetime, host access, and credential delivery. It intentionally reports discrete facts instead of a numerical "security score."

Runner trust lab

Inspect the execution boundary

Loading workload, runner, credential, and eligibility policy.

Loading runner trust model...

Apply these boundaries in a real fleet:

  • run untrusted merge-request code in an ephemeral environment without production credentials or host control;
  • keep deployment runners protected, narrowly tagged, and separate from general build capacity;
  • avoid the shell executor for code that must not share a persistent host boundary;
  • avoid privileged containers unless the workload and host are intentionally trusted;
  • rotate runner authentication tokens and remove stale runners;
  • assume that a compromised runner can expose every credential and network path made available to its jobs.

GitLab's runner security guidance and runner configuration guide describe executor isolation, protected runners, tags, and token risks. Review those documents against the exact GitLab offering and runner executor you operate.

Build once, then control promotion

A production job should promote the artifact that passed verification, not rebuild source under a different dependency or network state. Deployment policy then controls who may start the job, which environment it updates, and whether concurrent pipelines may modify the same target.

  1. 1

    Build

    Produce one artifact

    Record a version and digest. Keep the output and its provenance long enough to support promotion, rollback, and investigation.

  2. 2

    Test

    Verify the same bytes

    Run tests and scans against the produced package or image. Preserve reports as evidence rather than rebuilding during each gate.

  3. 3

    Approve

    Authorize the environment

    Use protected branches, protected environments, deployment approvals where available, and a manual confirmation for consequential actions.

  4. 4

    Deploy

    Serialize target changes

    Use a resource_group when overlapping jobs must not mutate the same environment at the same time, then verify health before promotion completes.

The deployment example requests a short-lived OpenID Connect ID token for a named audience, accepts only a default-branch pipeline, and serializes production changes. The token-consuming command is deliberately application-owned: its audience, subject, issuer, role mapping, and permissions must match the external identity provider.

Protected, serialized deployment with OIDC

See GitLab's current documentation for ID tokens, protected environments, and resource_group before applying the pattern. Feature availability and approval rules depend on the GitLab tier and offering.

Operate CI/CD as a production system

Pipeline speed matters only after correctness and isolation. Track the path from event to trustworthy feedback and deployment:

  • Creation health: pipeline creation errors, duplicate pipelines, and skipped jobs caused by unexpected workflow or rules combinations.
  • Queue health: queued duration by runner tag, eligible runner count, saturation, and jobs stuck because no runner matches all required tags.
  • Execution health: job duration, failure and retry rate, cancellation behavior, and variance by executor, image, project, and job family.
  • Transfer health: cache hit behavior, artifact upload and download failures, artifact size, and retention growth.
  • Delivery health: deployment frequency, lead time, failed deployment rate, rollback time, and overlap prevented by the environment's concurrency policy.
  • Fleet health: offline or stale runners, authentication-token rotation, autoscaling failures, disk pressure, and unexpected privileged workloads.

Use interruptible only for work that a newer pipeline can safely replace. Retry only failures that are plausibly transient and keep deployment commands idempotent. A generic retry can repeat an external side effect even when GitLab reports only one job.

Failure drill

Disable one runner pool, expire one cache, make one optional producer disappear, and start two deployments for the same environment. Verify that jobs queue on the intended tags, correctness survives a cold cache, needs: optional behaves as designed, and only one deployment mutates the target at a time.

No quiz questions available
Could not load questions file
Spotted an issue or have a better explanation? This page is open source.Edit on GitHub·Suggest an improvement