GitLab Runner Types: Shell, Docker, Kubernetes, and What Fits Magento
AI generated
CI/CD
.yml
GitLab Runner · Shell · Docker · Kubernetes · Magento
GitLab Runner Types
Shell, Docker, Kubernetes, and what fits Magento

The GitLab Runner is the engine of every pipeline: it executes the jobs defined in .gitlab-ci.yml. Which runner type fits Magento builds and deployments depends on isolation, performance, security requirements, and available infrastructure.

16 min read Shell Executor · Docker Executor · Kubernetes · Shared Runner · Self-hosted GitLab Runner 17+ · Magento 2.4.8 · PHP 8.4

1. What is a GitLab Runner?

A GitLab Runner is a process that runs on a machine, registers itself with a GitLab instance, and becomes available there to execute pipeline jobs. GitLab itself does not run jobs: it delegates execution to registered runners. The runner receives job definitions from GitLab, executes the defined scripts, collects logs and artifacts, and reports the result back to GitLab. Without at least one runner, no pipeline can run.

Runners are configured through executors, the mechanism by which the runner decides how to execute a job. The three most important executors are: Shell (directly on the host operating system), Docker (inside a container that is freshly started for each job), and Kubernetes (as a pod in a Kubernetes cluster). Each executor has different characteristics in terms of isolation, reproducibility, performance, and security. Choosing the executor is one of the most important decisions when setting up a GitLab pipeline.

Runners can be registered at three levels: project runners are only available to a specific project. Group runners are available to all projects in a GitLab group. Instance runners (formerly shared runners) are available to all projects on the GitLab instance. GitLab.com offers public shared runners that are suitable for simple build jobs, but are not recommended for production deployments to your own servers.

2. Shell executor: directly on the host

The shell executor runs pipeline jobs directly on the operating system of the runner host, in the context of the user under which the runner process runs. This is the simplest configuration: no container, no virtualization, no image downloads. The execution environment is static, whatever is installed on the runner host is available to every job. For Magento deployments that require SSH access to target servers, the shell executor is often the practical choice.

The main drawback of the shell executor is the lack of isolation: jobs run in the same user context and share the host filesystem. If two jobs run at the same time and access the same files, race conditions occur. In addition, the shell executor accumulates state over time, installed packages, cached files, environment variables, which can hurt build reproducibility. For build jobs that need a clean environment, the Docker executor is a better fit. For deployment jobs that run SSH commands on target servers, the shell executor is pragmatic and efficient.

# Shell Executor configuration in /etc/gitlab-runner/config.toml
[[runners]]
  name = "magento-deploy-runner"
  url = "https://gitlab.mironsoft.de/"
  token = "RUNNER_TOKEN"
  executor = "shell"
  shell = "bash"
  [runners.custom_build_dir]
    enabled = true
  [runners.cache]
    Type = "local"
    Shared = false
    [runners.cache.local]
      MaxCacheSize = 10240

# Job using shell executor, SSH access available via system ssh-agent
deploy:production:
  stage: deploy
  tags:
    - magento-deploy-shell    # Target this specific runner
  script:
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - rsync -az ./ "${DEPLOY_USER}@${DEPLOY_HOST}:${RELEASE_PATH}/"
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: manual

3. Docker executor: isolated containers

The Docker executor starts a new container for each job, runs the job inside it, and discards the container afterward. This guarantees a clean, isolated environment for every job, no state accumulation across jobs, no unexpected dependencies on previous runs. For build jobs that run composer install, npm ci, and setup:di:compile, the Docker executor is the recommended choice because it guarantees reproducibility: the same job with the same Docker image produces the same result, regardless of what happened on the runner host before.

The Docker executor requires a Docker daemon on the runner host. Jobs can use any Docker image specified in .gitlab-ci.yml via the image keyword. For Magento build jobs, an image such as php:8.4-cli is a good base, extended in before_script with the necessary system packages. Alternatively, a prebuilt Magento build image that already contains all required tools can be used, enabling faster build starts.

# Docker Executor configuration in /etc/gitlab-runner/config.toml
[[runners]]
  name = "magento-build-runner"
  url = "https://gitlab.mironsoft.de/"
  token = "RUNNER_TOKEN"
  executor = "docker"
  [runners.docker]
    image = "php:8.4-cli"
    pull_policy = ["always", "if-not-present"]
    volumes = ["/cache:/cache"]
    shm_size = 0
    privileged = false  # Never use privileged=true for build jobs

# Build job using Docker executor
build:magento:
  stage: build
  image: php:8.4-cli       # Fresh container for each job
  tags:
    - magento-build-docker
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths:
      - .cache/composer/
      - .cache/npm/
  before_script:
    - apt-get update -qq && apt-get install -y -qq git unzip nodejs npm libzip-dev
    - docker-php-ext-install zip bcmath intl
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
  script:
    - composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
    - npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
    - npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
    - php bin/magento setup:di:compile

4. Kubernetes executor: scalable pods

The Kubernetes executor starts a Kubernetes pod for each job, consisting of one or more containers. Once the job finishes, the pod is automatically deleted. This provides the strongest isolation of all executor types and the best scalability: Kubernetes can automatically provision new nodes when many jobs need to run at the same time. For larger teams or organizations that already run Kubernetes, the Kubernetes executor is the natural choice.

For Magento projects with a modest team size and simple infrastructure, the Kubernetes executor is overkill in most cases. Setting up and maintaining a Kubernetes cluster requires significant infrastructure expertise, and the overhead is hard to justify for simple Magento deployments. However, if you already run Kubernetes, for other applications, for example, you can use the Kubernetes executor for Magento build jobs and benefit from automatic scaling, pod isolation, and native Kubernetes integration with RBAC and network policies.

5. Shared runners: when they suffice and when they do not

GitLab.com offers shared runners available to all users that require no runner infrastructure of your own. They use the Docker executor with isolated containers and are well suited to many standard build jobs: running tests, checking code quality, installing dependencies. For Magento projects with public code, shared runners can be sufficient for the build and test stages.

For production deployments to your own servers, shared runners are not suitable, for several reasons. First, shared runners have no access to internal networks and therefore cannot open SSH connections to servers that are not publicly reachable. Second, shared runners share infrastructure with other users, which raises security concerns when production secrets are used in CI/CD variables. Third, shared runners are less predictable in terms of performance and availability. For production deployments, a self-hosted runner is mandatory.

6. Installing and registering a runner

GitLab Runner is installed via GitLab's official package repository. For Ubuntu/Debian: apt-get install gitlab-runner after adding the GitLab repository. After installation, the runner is linked to a GitLab instance via gitlab-runner register. This asks for the GitLab instance URL, a registration token (from the project or group settings), the runner name, and the executor type.

For Magento projects, a two-runner strategy is recommended: one runner with the Docker executor for build and test jobs, and one runner with the shell executor for deployment jobs. This separation ensures that build jobs always run in a clean container environment and deployment jobs have direct SSH access to the deployment infrastructure. Both runners should be configured with GitLab's tag system so that jobs are routed to the correct runner.

# Runner registration commands
# Install GitLab Runner on Ubuntu 22.04:
# curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
# sudo apt-get install gitlab-runner

# Register Docker Runner for build jobs:
# sudo gitlab-runner register \
#   --url "https://gitlab.mironsoft.de/" \
#   --registration-token "PROJECT_TOKEN" \
#   --description "magento-build-docker" \
#   --tag-list "magento-build,docker,php84" \
#   --executor "docker" \
#   --docker-image "php:8.4-cli"

# Register Shell Runner for deployment jobs:
# sudo gitlab-runner register \
#   --url "https://gitlab.mironsoft.de/" \
#   --registration-token "PROJECT_TOKEN" \
#   --description "magento-deploy-shell" \
#   --tag-list "magento-deploy,shell,production" \
#   --executor "shell"

# Reference runner via tags in .gitlab-ci.yml:
build:magento:
  tags:
    - magento-build          # Routes to Docker runner

deploy:production:
  tags:
    - magento-deploy         # Routes to Shell runner

7. Security aspects of runner types

The shell executor is the most security-critical runner type, because jobs run directly on the host system. If a malicious job or compromised code makes it into a pipeline, it has full access to everything the runner user can access: filesystem, network, other jobs, cached secrets. For that reason, shell runners should only be used for projects whose pipeline is fully under control, no direct execution of unreviewed code from merge requests by external contributors.

The Docker executor offers much better isolation because jobs run in their own containers. However, privileged: true should never be enabled in the Docker executor configuration, because it effectively grants root access to the host kernel and defeats container isolation. For shared runners, on which jobs from different users run, the Docker executor with correct configuration is the security baseline. For your own runners, network policies, resource limits, and regular runner image updates should also be put in place.

8. Runner types compared directly

Choosing the right runner type is a trade-off between simplicity, isolation, and scalability. For Magento projects of typical size, there are clear recommendations, but the optimal configuration depends on the specific infrastructure and security requirements.

Runner type Isolation Setup effort Recommended for Magento
Shell executor None, directly on host Minimal Deploy jobs, SSH access
Docker executor Container per job Moderate (Docker required) Build jobs, tests, quality
Kubernetes executor Pod isolation High (K8s cluster) Only with an existing K8s setup
Shared runner Container, shared No setup of your own Build/test only, not deploy

The optimal strategy for most Magento projects: a self-hosted runner with the Docker executor for build and test jobs, and a self-hosted runner with the shell executor for deployment jobs. This combination delivers reproducible builds through container isolation and practical deployment control through direct host access. The overhead of this two-runner setup is small, and the gains in security and reproducibility are considerable.

9. Summary

Choosing the right GitLab Runner type for Magento projects is not a minor technical detail, it is a foundational decision that affects the reproducibility, security, and maintainability of every pipeline job. Shell runners are simple and provide SSH access for deployments, but no isolation for build jobs. Docker runners guarantee reproducible builds through container isolation, but require Docker on the host. Kubernetes runners offer maximum scalability but are overkill for smaller Magento projects. Shared runners are enough for simple build jobs, but are not suitable for production deployments to your own servers.

The recommended setup for Magento: at least one self-hosted runner with the Docker executor for build and test jobs, and one self-hosted runner with the shell executor for deployment jobs. Both runners are configured via tags and targeted explicitly in .gitlab-ci.yml. This separation makes the system easier to maintain, more secure, and easier to debug, because build issues on the Docker runner and deployment issues on the shell runner are clearly separated from each other.

GitLab Runner for Magento: the essentials at a glance

Build jobs

Docker executor with a fresh container per job. Reproducible environment, no state accumulation. Image: php:8.4-cli or a custom Magento build image.

Deploy jobs

Shell executor on a dedicated host with SSH access to deployment servers. No container overhead, direct network access.

Shared runner

Only for build and test stages without secrets. Never use shared runners for production deployments, they have no access to internal networks.

Security

privileged: false always. Runner user with minimal permissions. Tags for job routing. Protected variables for production secrets.

10. Recommendation for Magento projects

Based on the characteristics of the different runner types, a clear recommendation emerges for Magento projects: for the build runner, a self-hosted runner with the Docker executor should be set up on a dedicated build server. The server needs Docker, enough RAM for Composer and npm (at least 4 GB), and fast disk access for the Composer cache. The runner configuration should enable caching for Composer packages and npm modules to reduce build times.

For the deploy runner, a shell executor on a server with network access to all deployment targets is recommended, ideally a bastion host or jump server in the same network zone as the web servers. The deployment user on the runner should only hold the SSH keys needed for deployment and no other permissions. The runner should not run on one of the deployment target servers itself, since that can cause conflicts if a deployment fails.

11. FAQ: GitLab Runner types for Magento

1Shell vs. Docker executor?
Shell: directly on the host, no isolation. Docker: fresh container per job, clean environment, deleted after the job. Docker guarantees reproducible builds.
2Shared runners for production deployments?
Not suitable. No access to internal networks, shared infrastructure with other users, a security risk for production secrets.
3Runner type for build jobs?
Docker executor. Reproducible environment, no state carryover between builds. Image: php:8.4-cli or a custom Magento build image.
4Runner type for deploy jobs?
Shell executor on a dedicated host with SSH access to deployment servers. Direct network access without container overhead.
5Registering a runner?
gitlab-runner register after installation. It asks for the GitLab URL, registration token, name, and executor type. The token comes from Settings > CI/CD > Runners.
6Never enable privileged: true?
Grants the container root access to the host kernel. Defeats container isolation. Jobs could compromise the host and read secrets from other containers.
7Assigning jobs to a runner?
Tags: a runner gets tags at registration. Jobs with tags: [tagname] only run on runners carrying that tag. Precise routing without configuration changes.
8One runner for build and deploy?
Technically possible, but not recommended. Splitting into two runners makes the system clearer, safer, and easier to debug.
9RAM needed for a build runner?
At least 4 GB. setup:di:compile needs 2 to 3 GB. Scale accordingly for parallel jobs. Swap is not a substitute for RAM.
10Kubernetes executor vs. Docker?
Kubernetes: automatic scaling, better isolation via resource quotas. Worthwhile only with an existing K8s cluster and many parallel builds. Overkill for smaller Magento projects.