Command Palette

Search for a command to run...

Hectal
PHASE 4Intermediate ~13 min· topic 2 of 4

Topic 4.2

GitLab Runners & Executors

In one line

A GitLab Runner is the agent that actually runs jobs — and its EXECUTOR determines exactly how: a Docker container, a shell on the host machine, or several other genuinely different isolation models.

0/4 · 0%

Key ideas

  1. 01

    A GITLAB RUNNER is the application that connects to GitLab and actually executes a pipeline's jobs — directly the same role as a GitHub Actions runner (Phase 2.1) or a Jenkins agent (Phase 3.1); every one of these three platforms needs SOME real machine actually doing the work, just with each platform's own specific terminology.

  2. 02

    GitLab offers SHARED RUNNERS (GitLab.com's own hosted infrastructure, available to any project with zero setup) and SELF-MANAGED runners you register yourself — directly the same hosted-versus-self-hosted trade-off Phase 2.4 already covered for GitHub Actions, just GitLab's own equivalent terminology and setup process.

  3. 03

    A runner's EXECUTOR determines HOW it actually runs a job — the docker executor runs each job inside a fresh, isolated Docker container (specified by the job's own image: key, as Topic 4.1's example already used), while the shell executor runs a job's commands DIRECTLY on the runner's own host machine, with no container isolation at all.

  4. 04

    The docker executor is genuinely the most common, recommended choice for most real use cases — each job gets a clean, isolated, reproducible environment defined purely by whatever image: it specifies, directly connecting to Docker's own course (a job effectively runs docker run <image> and executes its script inside it) — meaning two different jobs in the same pipeline can genuinely use two completely different images if needed.

  5. 05

    The shell executor genuinely sacrifices that isolation — jobs run directly on the runner's real filesystem, meaning state CAN leak between job runs (exactly Phase 2.4's self-hosted-runner concern, revisited here) unless the runner's own environment is deliberately kept clean; it's occasionally still the right choice when a job genuinely needs to interact with the host machine itself in a way containerization would prevent.

  6. 06

    docker+machine and Kubernetes executors take this further, dynamically PROVISIONING entirely new infrastructure (a cloud VM, a Kubernetes pod) for each job and destroying it immediately afterward — directly the same disposable, always-fresh model as a GitHub Actions hosted runner, just running on your own infrastructure rather than GitHub's, genuinely useful for scaling runner capacity elastically based on actual pipeline demand.

Code & diagrams

ExecutorIsolationLevelsdiagram

Genuinely different isolation guarantees, from none at all to fully fresh, disposable infrastructure per job.

Rendering diagram…
specifying-an-image.ymlmarkdown

Different jobs, different isolated images — genuinely simple with the docker executor.

unit-tests:
  stage: test
  image: eclipse-temurin:21-jdk    # this job's own isolated environment
  script:
    - mvn test

frontend-tests:
  stage: test
  image: node:20-slim              # a completely different image, same pipeline
  script:
    - npm ci
    - npm test

Explain it without notes

01

Why is the docker executor generally recommended over the shell executor for most real pipelines?

02

Two jobs in the same pipeline use completely different image: values. Why does this work cleanly with the docker executor but would be genuinely awkward with the shell executor?

Practice

01

If you have access to a GitLab runner (shared or self-managed), write a pipeline with two jobs using genuinely different images, and confirm each runs in its own correctly isolated environment.

02

Look up how to register a self-managed GitLab Runner and identify which executor type it defaults to, or would need to be explicitly configured for docker-based isolation.

Trade-offs

  • ↔

    The docker executor's isolation is genuinely safer and more reproducible, but it does add real per-job startup overhead (pulling and starting a fresh container each time) compared to the shell executor's direct, no-setup execution — for a genuinely simple, low-stakes internal tool where that isolation doesn't matter much, the shell executor's speed can be a reasonable, deliberate trade, though it remains the less common choice for most real production pipelines.

Done when you can

  • I can explain what a GitLab Runner is and its role, mapping it onto GitHub Actions runners and Jenkins agents.

  • I understand the difference between the shell and docker executors in terms of isolation.

  • I can specify different container images for different jobs within the same pipeline.