Named Runners
Named runners let you deploy isolated runner containers, each with its own config.toml. Jobs are dispatched to a named runner when any of their CI tags match the runner name.
Quick start#
Define a named runner in your config and tag jobs to use it:
# .glciconfig.toml
[runners.gpu]
config_template = """
[[runners]]
[runners.docker]
privileged = true
gpus = "all"
memory = "16g"
"""
# .gitlab-ci.yml
train-model:
tags: [gpu]
image: nvidia/cuda:12.0-devel
script:
- python train.py
When you run glci run, the train-model job is routed to the gpu runner container. All other jobs run on the default shared runner.
How it works#
The daemon’s RunnerManager coordinates three tiers of runner containers:
| Tier | Container name | When created |
|---|---|---|
| Shared | glci-runner-{suffix} | Always (default for all projects) |
| Per-project | glci-runner-{suffix}-{project} | When a project sets [runner] config_template |
| Named | glci-runner-{suffix}-{project}-{name} | When [runners.<name>] is defined |
Job dispatch#
- For each job, glci checks if any of its tags match a named runner name
- First tag match wins — the job is assigned to that named runner
- Unmatched jobs go to the default runner (shared or per-project)
- Named runners have
run_untagged=false— they only receive explicitly tagged jobs
Config templates#
Each named runner accepts a config_template (inline Go template) or config_template_file (path to a template file) that generates its config.toml.
Inline template#
[runners.gpu]
config_template = """
[[runners]]
[runners.docker]
gpus = "all"
privileged = true
volumes = ["/cache", "/usr/local/nvidia:/usr/local/nvidia:ro"]
"""
External template file#
[runners.gpu]
config_template_file = "runners/gpu-config.toml.tpl"
The template file uses the same Go text/template syntax. See Runner config templates for the full list of template variables.
Default runner templates#
The default runner ([runner]) can also use config_template to customize its config.toml. This is useful when you need to change runner-level settings globally without defining named runners:
# .glciconfig.toml
[runner]
config_template = """
[[runners]]
[runners.docker]
privileged = true
network_mode = "host"
shm_size = 2147483648
"""
When the default runner has a config_template, it gets its own per-project container (separate from the shared runner).
Multiple named runners#
You can define as many named runners as needed:
# .glciconfig.toml
[runners.gpu]
config_template = """
[[runners]]
[runners.docker]
gpus = "all"
privileged = true
"""
[runners.arm]
config_template = """
[[runners]]
[runners.docker]
platform = "linux/arm64"
"""
[runners.shell]
config_template = """
[[runners]]
executor = "shell"
"""
# .gitlab-ci.yml
train:
tags: [gpu]
script: python train.py
build-arm:
tags: [arm]
script: make build
deploy:
tags: [shell]
script: ./deploy.sh
lint:
# no tags — runs on the default runner
script: make lint
Runner name rules#
Runner names must match [a-zA-Z0-9][a-zA-Z0-9_-]*:
- Start with a letter or digit
- Can contain letters, digits, hyphens, underscores
- Names are case-sensitive
Lifecycle#
- Runner containers are created lazily on first use
- Containers are reused across pipeline runs (persistent)
- Containers are stopped when the daemon shuts down
- If a container is manually removed, the daemon recreates it on next use