Skip to content

Runner Profiles

A runner profile is the shape of a runner: the image to spawn, its resource limits, custom environment, image pull policy, and an optional private registry credential. Define it once at /runner-profiles and reference it from any number of workloads — two workloads serving different orgs can share one profile, so you describe the runner once.

Editing a profile applies to each referencing workload on its next reconcile pass: new spawns pick up the change, while in-flight runners keep their config until they finish and exit.

A label for the profile so you can pick it from a workload. Nothing about behaviour depends on it.

The Docker image Runaway spawns for each runner. The default is the Standard myoung34/github-runner image; it registers itself with GitHub using your PAT and runs a single job before exiting. Standard works for every runtime and sets START_DOCKER_SERVICE so dind and isolated-sysbox bring up their inner daemon (isolated-kata runs none). If your image lives in a private registry, attach a pull credential below.

The Standard image is not a drop-in ubuntu-latest. GitHub’s hosted image is tens of gigabytes of preinstalled toolchains; this one is a runner and little else. The practical consequence:

  • Its system interpreters are the base distribution’s, not current ones. A step that shells out to node or python before actions/setup-node or actions/setup-python has run gets whatever the distro ships, which is usually several majors behind. Installers are the common casualty — pnpm/action-setup runs its self-installer under the node on PATH, so placing it before setup-node can fail on a version no hosted runner would have given it. Put toolchain actions first.
  • Preinstalled tooling is absent. Databases, browsers, cloud CLIs and language runtimes you never had to think about on a hosted runner are not here. Install them in the job, or build your own image and point the profile at it.
  • /cache is the compensation. What a hosted runner gives you preinstalled, Runaway gives you warm: the first run pays for the download and every run after reads it locally. See Caching.
  • Memory limit (MB) — the hard cap applied to every runner container.
  • CPU limit — optional; leave it unset for no CPU cap.

These bound one runner; the number of runners is the workload’s concern.

On dind and isolated-sysbox the cap covers more than the runner. The inner Docker daemon and every container a job starts are children of the runner’s cgroup, so the limit is the ceiling for all of them together. A build that fits on a machine of that size can still be OOM-killed inside a runner capped at the same number, so size the profile for the whole job.

A JSON record of extra environment variables injected into every runner — chiefly for pointing package managers at your own registry proxies. See Custom environment variables for the validation rules and merge order.

Controls when Runaway pulls the runner image before spawning:

  • IfNotPresent — pull only when the image isn’t already on the host.
  • Always — pull on every spawn.
  • TtlHours — pull only if the last pull is older than the configured TTL (in hours). Keeps floating tags like :latest fresh without paying the pull cost on every spawn.

New profiles default to TtlHours with a 24-hour TTL; existing profiles preserve their prior pull behaviour. A pull failure hard-fails the spawn for that pass with a clear per-host error — Runaway never silently falls back to a stale cached layer.

Attach an encrypted registry credential to pull a runner image from a private registry. See Private runner images.