Choosing a GitLab Runner Executor: Shell, Docker, or Kubernetes?
Decide which GitLab Runner executor best balances isolation, speed, and scalability by comparing Shell, Docker, and Kubernetes options and seeing a concrete Docker configuration.
12 Jan 2026, 23:07 UTC

Problem & Takeaway
When a pipeline runs, the environment in which it executes can be the biggest source of bugs and security holes. Choosing the wrong GitLab Runner executor can leave your host system vulnerable or slow down your builds. The key decision is: how much isolation do you need versus how fast must the jobs run?
The takeaway: Shell provides speed but no isolation, Docker gives strong isolation with moderate overhead, and Kubernetes offers the most scalable isolation at the cost of cluster complexity.
Decision Guide
Before configuring a runner, answer these constraints:
- Do you need to run untrusted code? (High security)
- Do you have a Kubernetes cluster available?
- Is build time critical for small, internal jobs?
- Do you have resources to pull large images frequently?
Executor Comparison
| Executor | Isolation Level | Execution Speed | Complexity | Typical Use Case |
|---|---|---|---|---|
| Shell | None – runs on host kernel and filesystem | Fastest (no container overhead) | Low – simple config | Trusted internal projects, GPU‑heavy workloads, quick prototypes |
| Docker | High – each job in a fresh container | Medium – image pull + container start time | Medium – requires Docker daemon on runner | Most CI workloads, reproducible builds, image creation (DinD) |
| Kubernetes | High – job runs in its own pod | Variable – depends on pod scheduling and image pull | High – needs cluster, RBAC, network policies | Large scale, high‑concurrency pipelines, multi‑cluster environments |
Trade‑Offs Explained
- Security vs. Speed: Shell is fastest but any job can modify the host. Docker isolates jobs but adds container start latency. Kubernetes isolates at pod level and can enforce stricter network policies.
- Resource Management: Docker caches images locally, so subsequent jobs can reuse them, reducing latency. Kubernetes pulls images per pod, which can be mitigated with image pull policies.
- Scalability: Shell is limited by the host’s CPU/memory. Docker can run multiple containers in parallel, but the host’s resources still bound. Kubernetes scales by adding more nodes or using autoscaling, decoupling compute from the runner host.
- Operational Overhead: Shell needs less maintenance. Docker requires managing the Docker daemon and image cleanup. Kubernetes demands cluster ops, RBAC, and network configuration.
Concrete Implementation: Docker Executor with DinD
Below is a minimal config.toml for a runner that uses Docker and enables Docker‑in‑Docker (DinD) so that jobs can build images. Place this file in /etc/gitlab-runner/config.toml on the host where the runner is installed.
[[runners]]
name = "docker-builder"
url = "https://gitlab.example.com/"
token = "YOUR_RUNNER_TOKEN"
executor = "docker"
[runners.docker]
image = "docker:24.0.6"
privileged = true
volumes = [
"/var/run/docker.sock:/var/run/docker.sock",
"/cache:/cache"
]
pull_policy = "if-not-present"
shm_size = 256000
Key points:
privileged = trueallows the container to run Docker itself.- The
docker.sockvolume mounts the host Docker daemon; alternatively, usedocker:dindimage for isolated DinD. - Cache volume helps reuse layers between jobs.
Verification Steps
- Restart the runner:
sudo gitlab-runner restart(requires root). - Push a simple pipeline that echoes the Docker version:
job: script: - docker --version - Check the job log: it should show the Docker client inside the container, confirming DinD is active.
- Monitor resource usage:
docker statson the host during the job to verify container isolation and memory limits.
Limitations & Mitigations
- Privileged mode expands the attack surface; restrict runner access to trusted projects only.
- Large images can still slow pipelines; use multi‑stage Dockerfiles or a shared registry cache.
- If you need GPU access, consider a custom Docker image with the necessary drivers and mount the GPU device files.
When to Pick Each Executor
- Shell: Small teams, low security risk, or when you need direct host access.
- Docker: Most common CI workloads, need reproducible environments, moderate security.
- Kubernetes: Enterprise‑scale pipelines, multi‑tenant runners, or when you already run a cluster.
By aligning the executor choice with your constraints and verifying with a test job, you can avoid “dirty” builds and ensure consistent, secure pipeline runs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.