GitLab Runner Docker vs Kubernetes executor

The Docker executor suits teams that want runner hosts they can manage directly, while the Kubernetes executor suits teams already operating a cluster and wanting a pod per job. This page compares isolation, scaling, caching, debugging and the infrastructure each requires.

On this page

Which GitLab Runner executor fits your self-managed GitLab

Pick the Docker executor if your team has dedicated runner hosts and wants a simple footprint, and the Kubernetes executor if you already run a cluster and want a new pod for every job. Both executors give each build a clean build environment and support zero-configuration concurrent builds, so job isolation alone does not decide the choice. The difference is where jobs run and who operates that layer. The Docker executor runs jobs in containers on a host where Docker must be installed, and GitLab documents Podman as an alternative runtime. The Kubernetes executor calls the API of an existing cluster to create a pod for each job.

Three conditions usually decide it. The first is cluster skills. The Kubernetes executor adds a dependency on a cluster your team can patch, scale and debug, so if nobody already operates Kubernetes in production, the Docker executor keeps the moving parts fewer. The second is scaling. GitLab describes the Kubernetes executor as particularly suited to cloud-native environments with superior scalability and resource utilization, which matters most when job volume changes sharply. The third is clone reuse. If your pipelines depend on reusing a previous Git clone to save time, the Kubernetes executor needs persistent build volumes for each concurrency slot, so you must plan that storage before you choose it.

Before you commit, run a short comparison on both. Confirm that your team can maintain the runner host image or the cluster namespace, and write down who owns Docker or Kubernetes upgrades and patching. Time a representative pipeline with and without a reused clone, then check the build volume requirements with whoever manages your storage. Finally, read the GitLab Runner executors documentation for the settings your Runner version supports, because option names and defaults can change between releases and this page does not pin one.

Docker and Kubernetes executors compared on isolation, scaling and caching

This table compares the GitLab Runner Docker executor on runner hosts with the Kubernetes executor that creates a pod per job, row by row on isolation, infrastructure, scaling, clone reuse, caching, debugging and runtime options. Read each row against your own runner footprint, and treat any item marked as a point to confirm as a question for your vendor or test environment before you commit.

Decision factorDocker executorKubernetes executor
Isolation unitEach job runs in a container on the runner host, giving a clean build environment for every buildEach job runs in a new pod created through the cluster API, giving a clean build environment for every build
Infrastructure requiredDocker installed on each runner host; Podman is accepted as an alternative runtimeAn existing Kubernetes cluster that the runner can call through its API
Scaling modelScales by adding runner hosts or raising concurrency on existing hostsScales with the cluster; GitLab documents superior scalability and resource utilization for cloud-native environments
Zero-configuration concurrent buildsSupportedSupported
Clone reuse between jobsConfirm the build directory behavior for your runner configuration and pipeline layoutReusing a previous clone requires persistent per-concurrency build volumes that you provision and manage
Caching approachConfirm cache storage location and sharing rules for your runner configurationConfirm cache storage and volume sharing with your cluster storage class and runner settings
Debugging accessJob containers run on a host you can log into directly; confirm which host logs and container inspection your team needsJob pods are ephemeral and live in the cluster; confirm log retention and pod inspection with your cluster administrators
Operating skills neededHost administration, Docker runtime upkeep and runner registrationKubernetes administration, RBAC, storage classes and cluster upgrades, which GitLab's cloud-native guidance assumes

How the Docker executor runs jobs on runner hosts

The Docker executor gives each job a clean build environment by running it inside a container, but every container is started on a runner host that you manage. GitLab's executor documentation says the Docker executor requires Docker on that host and accepts Podman as an alternative runtime. The runner process on the host picks up jobs from GitLab and launches containers from images, so the host is where your build capacity, container runtime and network access all live. Confirm with GitLab Runner's documentation which Docker or Podman versions your runner release supports before you standardize on one.

Your team owns the runner host operating system, the patch cadence for Docker or Podman, the disk and memory headroom that concurrent containers consume, and the cache and image storage on each host. Patching is a recurring task: a kernel or container runtime update may require draining jobs from the host first. Scale works by adding hosts and registering more runners, so capacity planning becomes a question of how many hosts you run and how they are sized. Build a runbook for host replacement and decide whether hosts are long-lived or rebuilt from images, since long-lived hosts accumulate state that can leak between jobs.

This is the simpler choice when you run a small number of runners, your jobs need no more than a few hosts, and your team has no Kubernetes operations skills. You avoid operating a cluster and its control plane, and a single host can be debugged directly with standard container tools. It stops being simpler once you need elastic scaling across many runners, uniform host images across several sites, or the isolation and autoscaling patterns covered in the Kubernetes section below.

How the Kubernetes executor creates a pod for each job

The Kubernetes executor turns each CI job into a short-lived pod on a cluster you already run, which gives every build a clean environment and lets capacity follow demand.

  1. Confirm the cluster and runner prerequisites

    Before any job runs, a Kubernetes cluster must already exist and be operated by your platform team. The GitLab Runner executor documentation describes the Kubernetes executor as using an existing cluster, so cluster provisioning, control plane health and node capacity are prerequisites, not things the runner creates. The runner needs credentials and permissions to call the cluster API in the target namespace. You know this step is complete when the runner registers and can reach the API server from its own host or pod.

  2. Runner calls the cluster API for a job

    When GitLab assigns a job to a runner using the Kubernetes executor, the runner calls the cluster API and asks for a new pod that matches the job's image and settings. The request passes through the cluster's own authentication and authorization, so the RBAC rules you set for the runner's service account decide what it may create. Check the runner logs or the namespace events to confirm the request was accepted before the pod starts.

  3. Scheduler places the job pod on a node

    The Kubernetes scheduler assigns the new job pod to a worker node with enough free CPU and memory. This is where scalability and resource utilization come from: many short jobs share the same node pool, and the cluster autoscaler, if you have configured one, can add nodes when pending pods cannot be placed. Pending pods that never schedule usually point to resource requests, node selectors or quota limits, so review those values before blaming the runner.

  4. Job runs in its own pod

    The job's build and helper containers run inside the pod the runner created. Each job starts from the declared image, so the environment is clean for every build and does not carry over files or installed packages from earlier jobs. Any state the job needs, such as dependency caches or a previous clone, must come from a configured cache or a persistent volume, not from the node itself. You know the job is running when its trace streams in the GitLab job log and the pod shows a running status.

  5. Reuse a previous clone only with persistent volumes

    By default a fresh pod means a fresh clone. GitLab's executor comparison notes that reusing a previous clone on Kubernetes requires persistent per-concurrency build volumes. Each concurrent job slot needs its own volume so that two jobs never write to the same working tree. Plan the storage class, volume size and cleanup for those volumes as part of the cluster design, and confirm with your runner configuration reference how the build directory is mounted before you rely on clone reuse for speed.

  6. Collect results and artifacts before teardown

    When the job's scripts finish, the runner collects the job status and uploads any artifacts or cache entries to the storage GitLab is configured to use. Results must leave the pod before it is removed, because the pod's own filesystem is discarded. Check that the job log shows the final status and that artifacts appear in the GitLab job page before you treat the step as finished.

  7. Remove the pod and verify cleanup

    After the job completes, the runner deletes the job pod, which releases its CPU, memory and any ephemeral storage back to the cluster. Persistent build volumes, if you configured them, remain by design and need their own retention rule. Verify cleanup by listing pods in the runner namespace after a batch of jobs and confirming no orphaned job pods remain. Orphaned pods or growing volumes are the first signs that cleanup or quota settings need attention.

What infrastructure each executor needs before the first job runs

The Docker and Kubernetes executors both depend on infrastructure that must exist before a single job runs, but the dependencies sit in different places. One puts the weight on runner hosts and a container runtime, the other on a cluster whose control plane and etcd someone must operate. Every card below is a prerequisite to confirm before choosing.

Runner hosts and container runtime

The Docker executor needs Docker installed on each runner host, and GitLab's executor documentation says Podman is accepted as an alternative runtime. Each host runs jobs in containers, so the team must size CPU, memory and disk per concurrent job and patch the host OS and runtime on its own schedule. Confirm which runtime your image and privilege policy allows before rollout.

An existing Kubernetes cluster

The Kubernetes executor does not install a cluster. It calls the cluster API to create a pod for each job, so the cluster must already exist, be reachable from the runner and have capacity and quotas for build pods. Confirm who owns that cluster, how upgrades are scheduled and whether the platform team will accept build workloads on it.

Control plane and etcd layout

A cluster that runs builds is still a cluster that must be operated. Kubernetes documentation says etcd should run with an odd number of members, recommends five members in production and requires a backup plan, with snapshots taken by etcdctl. Kubeadm HA guidance describes stacked and external etcd topologies with at least three control plane nodes. Confirm these settings against your own cluster before counting on it for CI.

Persistent volumes for clone reuse

GitLab's comparison table says reusing a previous clone on Kubernetes requires persistent per-concurrency build volumes. The Docker executor can keep the clone on the runner host, while Kubernetes needs storage classes, PVC lifecycle rules and a plan for stale or corrupted volumes. Ask your storage team whether the chosen class supports the access mode and performance your jobs need.

Registry and cache storage

Every job pulls images and may read or write a shared cache, so registry reachability and cache storage become hard dependencies. Docker runners typically share a host-local or network cache, while Kubernetes runners often need an object store or shared volume that survives pod deletion. Confirm where images come from, whether the network allows pulls in an air-gapped setup, and how cache growth is capped.

Choosing an executor by team and environment

If your team already has a handful of Linux hosts and no Kubernetes cluster, the Docker executor is the direct fit. GitLab's executor documentation says it provides clean build environments through containers and requires Docker on the runner host, with Podman accepted as an alternative runtime. You avoid standing up a cluster just to run jobs, but you take on the runner host lifecycle yourself: patching the host, Docker, and the runner, and sizing capacity by hand.

  • Deciding condition: job volume fits a small, fixed pool of hosts, and nobody on the team is already responsible for a Kubernetes control plane.
  • Work it creates: host provisioning, Docker or Podman updates, runner registration, and capacity planning as the pipeline count grows.
  • Isolation: each job runs in a fresh container, but containers share the host kernel, so the host itself must be treated as part of the trust boundary.
  • Caching and clones: the host keeps its own cache, which is simple to reason about but is not shared across hosts unless you configure it.
  • Scaling: adding capacity means adding hosts or configuring autoscaling on the runner, which you should confirm against the runner documentation for your version.

Before committing, confirm with your runner administrators how many concurrent jobs a host can serve in your own environment, and who owns patching the hosts.

How isolation, secrets and debugging differ in practice

Both executors give each build a clean environment, but the boundary around that build is different. With the Docker executor, each job runs in a container on a runner host, so the shared surface is the host kernel, the Docker daemon and anything else that host carries. With the Kubernetes executor, each job runs in a pod inside a cluster shared with other workloads, so the boundary depends on namespaces, RBAC, network policy and Pod Security Standards. Decide first which boundary your risk model accepts, then confirm the controls that enforce it. Ask your runner and cluster owners which namespaces, service accounts and node pools the runner will use, and whether privileged containers or host mounts are allowed in the job's namespace.

Secrets need the most care on the Kubernetes side. Kubernetes stores Secrets unencrypted in etcd by default, so a platform team has to confirm that encryption at rest is enabled for the cluster before any CI credential is placed there. Access to Secrets should be limited with least-privilege RBAC, and list and watch permissions on Secrets should be restricted because they expose values to anyone who holds them. Some teams prefer an external store through the Secrets Store CSI Driver. On the Docker executor, the equivalent question is where variables and registry credentials live on the runner host, who can read the runner configuration file and whether the host's file permissions and backups protect those values. Write both answers into your review checklist.

Debugging differs most after a failure. A Docker executor job can often be reproduced on the runner host itself, by re-running the same image with the same variables and inspecting leftover state, although that state should not be trusted to persist. A Kubernetes executor pod is removed after the job finishes, so there is no host to log into and no pod to inspect unless the job's output and the cluster's event and container logs were kept. Plan log retention in the cluster's logging stack before go-live, and confirm with your platform team how long pod logs and Kubernetes events survive, who can read them and whether job logs are stored in GitLab with the retention you need. Without that plan, a failed deployment in a pod-per-job setup may leave nothing to examine.

Operating each executor: upgrades, capacity and skills

This table compares what it takes to keep each GitLab Runner executor patched, sized, monitored and staffed over time. Read each row as a day-two question, and use the Kubernetes rows only with the cluster's own upgrade calendar in view.

Operating areaDocker executor on runner hostsKubernetes executor on a cluster
Runner and dependency upgradesYou upgrade GitLab Runner on each host and keep Docker or Podman patched there. Confirm the runner release cadence and supported versions in the GitLab Runner documentation.You upgrade the runner deployment and the cluster it schedules onto. Confirm the runner release cadence in the GitLab Runner documentation before planning windows.
Kubernetes version supportNot applicable. The host OS and container runtime are the lifecycle to track.The project maintains the three most recent minor releases; 1.37, 1.36 and 1.35 were listed as of September 2026. Plan upgrades before a version leaves support.
Upgrade orderUpgrade hosts in batches, draining jobs first. The runner host and Docker version are the only ordering concern.The version skew policy requires kube-apiserver to be upgraded one minor version at a time, before controller-manager, scheduler and kubelets. Kubelets may trail the API server by up to three minor versions.
Capacity managementAdd or remove runner hosts and set concurrency per host. Scaling is manual unless you build autoscaling around the runner.Pods are created per job against cluster capacity, so node pools, quotas and cluster autoscaling set the ceiling. Size the cluster for peak concurrent jobs, not average load.
Monitoring focusHost CPU, memory, disk, Docker daemon health and runner job queues. Watch disk growth from images and caches on each host.Cluster health, node pressure, pod scheduling delays, persistent volume usage for build caches and API server load. Confirm which metrics the runner exposes in the GitLab Runner documentation.
Control plane and etcdNot applicable to runner hosts.If you run your own control plane, kubeadm documents stacked or external etcd topologies with at least three control plane nodes. Etcd should have an odd member count, and Kubernetes recommends five members in production.
Team skills requiredLinux administration, Docker or Podman, and host configuration management. Most platform teams already have these skills.Kubernetes administration, RBAC, storage classes, network policy and etcd backup and restore. This is a larger skill set and usually needs a named owner.
Secrets and access handlingRunner tokens and registry credentials sit on hosts. Restrict host access and rotate tokens on a schedule you document.Secrets are stored unencrypted in etcd by default. Confirm encryption at rest and least-privilege RBAC before storing registry or deploy credentials in the cluster.

Questions teams ask before choosing a GitLab Runner executor

Does the Kubernetes executor need an existing cluster?

Yes. GitLab's executor documentation describes the Kubernetes executor as one that uses an existing Kubernetes cluster and calls that cluster's API to create a new pod for each job. It does not install or run the cluster for you. If your organization has no cluster today, the executor choice is really a platform choice, and that decision carries its own cost in control plane design, etcd backups, upgrades and access control. Confirm with your platform team whether a cluster already exists, who operates it, and whether it has capacity and isolation rules that allow CI workloads to run in it. The GitLab Runner executors documentation sets out the requirements for each option.

What drives the cost and effort of each executor choice?

The main cost components are the runner hosts or cluster capacity, the people who build and patch them, and the time spent on troubleshooting. The Docker executor needs Docker on each runner host, so cost rises with the number of hosts you size, patch and monitor. The Kubernetes executor shifts cost toward cluster operations, but it can use resources more efficiently when many jobs run in bursts. Costs go up with build concurrency, large caches, long-lived build volumes and the number of separate clusters or environments. They go down when runners share capacity and autoscaling reclaims idle resources. Ask any vendor or partner for a written quote that separates one-time setup from recurring operations, and that lists who runs upgrades, monitoring and on-call support.

What does the work need from our own staff?

The Docker executor asks for Linux host administration, Docker or Podman runtime management, runner registration, image hygiene and cache handling on each host. The Kubernetes executor asks for everything a cluster needs, including RBAC, namespace and resource quota design, network policy, storage classes for persistent build volumes, and secret handling. Kubernetes stores Secrets unencrypted in etcd by default, so encryption at rest and least-privilege access must be configured deliberately. Your staff should be able to read pod logs, inspect events, and reason about scheduling failures. If that skill set is thin, plan for training or outside help before you commit to the Kubernetes route.

How long does a migration between executors take?

Duration depends on how many pipelines depend on executor-specific behavior, how much of the build relies on host paths, Docker-in-Docker, privileged containers or a persistent clone, and how many projects share runner configuration. Moving from Docker to Kubernetes usually means rewriting runner configuration, redesigning cache and artifact handling, and retesting pipelines in a staging project before any production traffic moves. GitLab's comparison table notes that reusing a previous clone on Kubernetes requires persistent per-concurrency build volumes, so that behavior needs explicit design. No migration duration is supplied for this topic. Ask for a written timeline based on your pipeline inventory and confirm it against a pilot project.

Can we run this without outside help?

Many teams can, provided they already operate Linux hosts or a Kubernetes cluster and have someone who owns CI infrastructure. The harder questions are operational: patching runners on schedule, keeping images current, handling secrets, and debugging failed jobs at odd hours. For the Kubernetes route, the cluster itself carries work that does not disappear with the executor, including etcd backups and version upgrades that must follow the Kubernetes version skew policy. DeployOpen plans, implements, hardens, backs up, upgrades, documents and supports self-hosted open-source platforms in your own infrastructure, typically under a fixed-scope agreement with written deliverables, with ongoing support available as a retainer. Ask any partner what is in scope, who holds the on-call duty, and what happens at handover.

Does Podman change the Docker executor's trade-offs?

It can change the runtime requirement but not the fundamental choice. GitLab's executor documentation says the Docker executor requires Docker on the runner host and accommodates Podman as an alternative runtime. That matters if your security policy discourages running a Docker daemon on build hosts, or if your Linux distribution standardizes on Podman. It does not remove the need to manage the host, its images and its caches, and it does not give you the pod-level scheduling and autoscaling of the Kubernetes executor. Confirm with your security team how the runtime handles privileged jobs, rootless operation and image builds, because those behaviors are where teams most often find surprises.

Which executor gives stronger isolation for each build?

Both executors give each build a clean environment, according to GitLab's comparison table, so neither leaks state between jobs by default. The difference lies in what surrounds the job. A Docker executor on a shared host depends on the host's kernel, Docker daemon configuration and what other jobs can reach on the same machine. A Kubernetes executor depends on pod security settings, namespace boundaries, network policy and RBAC. Review the Pod Security Standards and your cluster's admission controls before relying on pod boundaries for untrusted code. Privileged builds weaken either model, so restrict them to dedicated runners and confirm the design with your security reviewers.

Which compliance evidence should we expect from either setup?

Neither executor produces a certificate or audit report on its own. Compliance readiness comes from the controls you document and can show: access to runner registration tokens, separation of production and build credentials, logging of job activity, patch records for runner hosts or cluster nodes, and backup and restore tests. A Kubernetes setup adds cluster-level evidence, such as RBAC reviews and encryption-at-rest configuration, while a Docker setup adds host-level evidence. Independent auditors and certification bodies assess these controls, and DeployOpen prepares systems, controls and evidence for those assessments without issuing any report itself. Ask your assessor which artifacts they expect before you pick an executor.

What drives cost and what switching later involves

The main cost of either executor is the infrastructure underneath it, not the GitLab license. With the Docker executor, you pay for the runner host capacity, Docker or Podman on that host, and the storage used for caches. With the Kubernetes executor, you pay for cluster capacity that runs job pods, and you also carry the cluster itself: control plane nodes, etcd backups and upgrades. Those recurring costs rise with concurrent jobs, job length and how much cache you keep. Confirm with your own platform team how many nodes and how much storage your peak concurrency needs before you compare any quote.

GitLab licensing is a separate line item. GitLab Free, Premium and Ultimate are all available for self-managed installations, and the tier you already hold does not change which executor you can use. Current tier prices are on the GitLab pricing page, where Premium is listed per user per month billed annually and Ultimate is custom priced. Also account for people: the Kubernetes route usually needs staff who can run the cluster, while the Docker route needs staff who can patch and rebuild runner hosts. Ask any implementation partner for a written scope that separates these one-time build work from recurring support, upgrades and testing.

Switching later costs more than the pipeline files suggest. A .gitlab-ci.yml job often moves between executors with little change, but the surrounding configuration does not. Runner tags, the config.toml executor settings, cache locations, and per-concurrency build volumes for clone reuse all have to be rebuilt, and the host or cluster beneath them has to be provisioned again. Before you choose, decide whether clone reuse matters to your jobs, and write down which runner tags your pipelines depend on. A partner can estimate the rebuild effort only from a written scope that lists those tags, volumes and infrastructure.

How DeployOpen scopes, delivers and supports GitLab runner deployments

DeployOpen plans, implements, integrates, documents and supports self-hosted open-source platforms inside the client's own infrastructure, and GitLab Runner is handled the same way. The work starts from a written scope that decides which executor fits your job mix, your isolation requirements and the infrastructure you already run.

How we scope

  • Written scope names which runner executor, Docker or Kubernetes, each project group will use and why.
  • Scope lists the runner hosts or cluster, cache storage and network paths the chosen executor needs.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before any work begins.

How we build

  • Runners are installed and configured in your environment, including concurrency limits and tagging for job routing.
  • Kubernetes runners get namespace, RBAC and pod security settings, while Docker runners get host hardening and runtime setup.
  • Clone reuse, build caching and volume settings are tested against your pipelines before the runner moves into use.

How we hand over

  • Documentation covers the executor configuration, sizing assumptions and the steps for adding or removing runners.
  • Runbooks describe how to read job logs, reproduce a failed build and trace whether a fault sits in the pipeline or the executor.
  • Handover includes a walkthrough with your platform and security teams so they can operate the runners without us.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers, scoped separately from the build.
  • Runner version upgrades are planned against the GitLab release cadence and the upgrade stops your instance requires.
  • Ask any provider to confirm in writing how runner patching, cluster upgrades and incident response are divided between parties.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.