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.
Key ideas
- 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.
- 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.
- 03
A runner's EXECUTOR determines HOW it actually runs a job — the
dockerexecutor runs each job inside a fresh, isolated Docker container (specified by the job's ownimage:key, as Topic 4.1's example already used), while theshellexecutor runs a job's commands DIRECTLY on the runner's own host machine, with no container isolation at all. - 04
The
dockerexecutor is genuinely the most common, recommended choice for most real use cases — each job gets a clean, isolated, reproducible environment defined purely by whateverimage:it specifies, directly connecting to Docker's own course (a job effectively runsdocker 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. - 05
The
shellexecutor 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. - 06
docker+machineand 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
Genuinely different isolation guarantees, from none at all to fully fresh, disposable infrastructure per job.
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 testExplain it without notes
Why is the docker executor generally recommended over the shell executor for most real pipelines?
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
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.
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.