CI Runners
A runner is an agent process that polls Vetrix for pending jobs, executes them, and streams logs back. Runners authenticate with a registration token issued by an admin.
Registering a runner
Only admins can register runners. Use the admin API or the web UI under Admin → Runners.
curl -X POST https://<vetrix-host>/api/v1/admin/runners \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "linux-amd64-01",
"tags": ["linux", "amd64", "docker"]
}'
Response:
{
"token": "runner_...",
"runner": {
"id": "01HZ...",
"name": "linux-amd64-01",
"tags": ["linux", "amd64", "docker"],
"status": "offline"
}
}
The token field is shown once only. Copy it immediately — it cannot be retrieved again. The stored value is a SHA-256 hash and cannot be reversed.
Starting a runner
The runner binary is vetrix-runner. Pass the token and endpoint at startup:
vetrix-runner \
--url https://<vetrix-host> \
--token runner_... \
--name linux-amd64-01 \
--concurrency 4
Or use environment variables:
export VETRIX_RUNNER_URL=https://<vetrix-host>
export VETRIX_RUNNER_TOKEN=runner_...
vetrix-runner --name linux-amd64-01 --concurrency 4
The runner registers itself on first start and then long-polls for jobs.
Runner configuration file
vetrix-runner.toml:
url = "https://<vetrix-host>"
token = "runner_..."
name = "linux-amd64-01"
concurrency = 4
[docker]
privileged = false
volumes = ["/cache:/cache"]
[executor]
type = "docker"
image = "alpine:3.19" # fallback image if job doesn't specify one
Job routing
Jobs are routed to available runners. All registered runners poll for pending jobs and pick up work from the queue.
Runner lifecycle
| Status | Meaning |
|---|---|
offline |
Never connected, or not seen in the last 60 seconds |
idle |
Connected and waiting for a job |
busy |
Currently executing one or more jobs |
Runners update their last_seen_at timestamp every 30 seconds. A runner that stops updating is marked offline after 60 seconds.
Listing runners
curl https://<vetrix-host>/api/v1/admin/runners \
-H "Authorization: Bearer <admin-token>"
Deleting a runner
Deleting a runner invalidates its token. Any in-flight jobs on that runner are marked failed.
curl -X DELETE https://<vetrix-host>/api/v1/admin/runners/<runner-id> \
-H "Authorization: Bearer <admin-token>"
Docker executor
The Docker executor is the default and recommended choice. Each job gets a fresh container from the specified image.
Runners must have Docker installed and the runner process must have socket access:
# Add the runner service account to the docker group
usermod -aG docker vetrix-runner
Containerized worker (docker-compose
--target worker): group name membership does not carry into a container — the worker must be granted the socket's numeric owning GID viagroup_add. Seeworker-docker-socket.md.
For security, privileged: false is the default. Enable only for jobs that need it (e.g., Docker-in-Docker builds).
Docker-in-Docker
build-image:
stage: build
image: docker:24
variables:
DOCKER_HOST: unix:///var/run/docker.sock
commands:
- docker build -t myapp .
Running as a systemd service
/etc/systemd/system/vetrix-runner.service:
[Unit]
Description=Vetrix CI Runner
After=network.target docker.service
[Service]
User=vetrix-runner
ExecStart=/usr/local/bin/vetrix-runner --config /etc/vetrix-runner/config.toml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
systemctl enable --now vetrix-runner
Autoscaling
For dynamic workloads, runners can be deployed as Kubernetes pods or EC2 spot instances. The runner process itself is stateless — scale by increasing concurrency on existing runners or by registering additional runners and adding them to the same pool.
Resource limits (admin-configured)
Admins can cap runner resource usage instance-wide. See ../admin/cicd.md for the ci.max_job_timeout, ci.max_concurrency, and allowed Docker image settings.