Self-managed runners control cost, hardware, network access and security for every job you run.
GitLab Runner is a Go binary that polls GitLab for jobs and runs them with an executor:
docker: each job in a fresh container from the job'simage; the default choice.kubernetes: each job as a pod in a cluster; scales with the cluster.shell: directly on the host; simple but jobs share the machine and its state.docker-autoscalerandinstance: create cloud VMs on demand through fleeting plugins; the successor to the deprecated docker+machine autoscaling.
You create a runner in the UI (project, group or instance level), which gives an authentication token starting with glrt-, then run gitlab-runner register with it on the host. The runner's settings live in config.toml: concurrent caps jobs across the whole process, and each [[runners]] section has its executor settings, such as the default image, privileged mode and volumes.
Jobs are routed with tags: a runner configured with tags gpu and linux only takes jobs whose tags: are a subset of its tags. Runners can also be set to run untagged jobs or only protected branches. A protected runner is the right place for deploy jobs with production access.
Security: privileged = true (needed for Docker-in-Docker) gives jobs root-equivalent access to the host. Isolate such runners and never share them with untrusted projects.
Example
# Register a runner using the glrt- token from the UI
gitlab-runner register --non-interactive \
--url https://gitlab.example.com \
--token "$RUNNER_TOKEN" \
--executor docker --docker-image alpine:3.22
# /etc/gitlab-runner/config.toml (excerpt)
# concurrent = 8 # max parallel jobs for this process
# [[runners]]
# name = "docker-gpu"
# executor = "docker"
# [runners.docker]
# image = "alpine:3.22"
# privileged = false
# .gitlab-ci.yml side: route a job by tags
# train:
# tags: [gpu, linux]
gitlab-runner verify && gitlab-runner listRemember
- The runner polls GitLab; executors decide how jobs are isolated
- Tags route jobs; concurrent caps parallel jobs
- Privileged runners are root-equivalent; keep them isolated and protected
Watch out for
- Using the shell executor for untrusted code; jobs share the host and its leftovers.