GitLab CI/CD Associate study materials
GitLab CI/CD Associate study resources

GitLab CI/CD Associate: Runners, Executors, and Job Scheduling

GitLab CI/CD Associate · Work through your exam, one topic at a time.

All guide sections

Runners, Executors, and Job Scheduling

This domain covers which runner picks up a job, what the executor provides, and how jobs are delayed, serialised, or cancelled.

Runner selection

Runners are registered at instance, group, or project level. A job's tags: lists requirements; a runner is eligible only if it carries every tag the job lists. A job with no tags runs only on runners configured to accept untagged jobs - a common reason a job sits in pending forever. Protected runners accept jobs only from protected branches and tags. rules and only/except decide whether a job exists; tags decide which runner runs it, and both must succeed.

Executors

  • shell runs on the runner host, inheriting installed tools and accumulated state - fast, but jobs can pollute each other.
  • docker runs each job in a fresh container from image:; services: starts sidecar containers (a database, Docker-in-Docker) reachable by hostname, and pull_policy controls when images are fetched.
  • kubernetes creates a pod per job; docker autoscaler provisions ephemeral VMs; ssh and virtualbox cover special cases.

Because the docker executor starts a clean container, anything not baked into the image or restored from cache/artifacts is missing - the usual cause of "works on the shell runner, fails in CI".

Scheduling and concurrency

config.toml sets the runner's concurrent limit, and each runner can also carry a job limit. Pipeline schedules (cron defined in the UI or API) create pipelines with CI_PIPELINE_SOURCE == "schedule" and can inject their own variables. when: delayed with start_in: 30 minutes holds a job for a fixed wait. resource_group serialises jobs that would otherwise mutate the same environment concurrently. interruptible: true combined with auto-cancel redundant pipelines stops superseded jobs.

Worked example

deploy:
  tags: [docker, production]
  resource_group: production
  interruptible: false
  script: ./deploy.sh

Reasoning: only runners holding both docker and production are eligible, so a runner tagged only docker will never pick the job up. resource_group: production ensures two pipelines cannot deploy at once. interruptible: false protects the deploy from being auto-cancelled mid-run.

Traps

  • Adding tags that no runner carries, then debugging the YAML instead of the runner list.
  • Expecting shared runners to be available when the project has them disabled or its compute minutes are exhausted.
  • Assuming concurrent changes stage ordering - stages remain sequential.
  • Running untrusted merge request code on a shell executor.