Key points
- Runner registration is trusted by service JWT and TLS material plus the ejected-runner blocklist.
- Routing tables use the effective view: paused or unreachable runner IDs stay visible for diagnosis, but only reachable dispatch-enabled runners are treated as dispatchable targets.
- An ordinary network disconnect keeps the registration available for reconnect. A reconnected runner keeps
last_disconnected_atand shows as recovered or degraded during the recovery window. - Deliberate removal disconnects the runner, clears dispatcher status, and adds its ID to
ejected_runner_ids. - An explicit empty
runner_scopesvalue means all scopes. - Generated installs preserve the friendly name as
runner_nameand use a unique suffixedRUNNER_IDfor dispatcher identity.
Field reference
RUNTIMErunnerstringOptionaldocker
Execution runtime the runner provides. Hybrid deployments use a comma-separated list.
RUNTIME=docker,kubernetesdocker, kubernetes
config/config.go
RUNNER_IDrunnerstringRequiredGenerated with a unique suffix
Dispatcher identity for this runner. Generated installs add a unique suffix to the friendly name.
RUNNER_ID=eu-build-01-7f2a- Deliberate runner removal adds this ID to
ejected_runner_idsand blocks reconnection.
config/config.go
RUNNER_NAMErunnerstringOptionalNone
Friendly name preserved by generated installs and shown in the dispatcher fleet view.
RUNNER_NAME=eu-build-01RUNNER_SCOPESrunnerstringOptionalAll scopes
Scopes this runner accepts work for. An explicit empty value means all scopes.
RUNNER_SCOPES=platform/production,platform/stagingconfig/config.go
RUNNER_CAPACITYrunnerintegerOptionalRunner default
Number of concurrent runs this runner advertises to the dispatcher.
RUNNER_CAPACITY=4config/config.go
DOCKER_NETWORK_NAMEdocker runnerstringOptionalDocker bridge
Network joined by step containers. Blank, bridge, or default keeps normal egress; none disables step networking; any other value joins that network.
DOCKER_NETWORK_NAME=nonebridge, default, none, <custom network name>
Use none when step workloads must run without egress, or a dedicated network for controlled egress.
config/config.go
RUNTIME_POOLSkubernetes runnermapOptionalNone
Named Kubernetes runtime pools selectable through pipeline or step runtime_pool.
RUNTIME_POOLS=gpu:node-role=gpuconfig/config.go
KUBERNETES_NAMESPACEkubernetes runnerstringOptionalRunner namespace
Namespace where the runner creates agent pods, step pods, and workspace PVCs.
KUBERNETES_NAMESPACE=nopsai-runnersconfig/config.go
KUBERNETES_SERVICE_ACCOUNTkubernetes runnerstringOptionalChart-managed runner service account
RBAC-bearing service account used by the runner Deployment and agent pods.
KUBERNETES_SERVICE_ACCOUNT=nopsai-runnerdeploy/helm/nopsai
KUBERNETES_WORKLOAD_SERVICE_ACCOUNTkubernetes runnerstringOptionalChart-managed no-RBAC service account
Separate service account for step pods, deliberately without cluster permissions.
KUBERNETES_WORKLOAD_SERVICE_ACCOUNT=nopsai-workloadKeeping step pods on a no-RBAC account is what stops workload code from calling the Kubernetes API.
deploy/helm/nopsai
KUBERNETES_IMAGE_PULL_SECRETSkubernetes runnerstring[]OptionalNone
Infrastructure-owned pull secrets attached to runner and step pods for private registries.
KUBERNETES_IMAGE_PULL_SECRETS=regcredconfig/config.go
KUBERNETES_STORAGE_CLASSkubernetes runnerstringOptionalCluster default
Storage class used for the agent-owned workspace PVC.
KUBERNETES_STORAGE_CLASS=fast-ssdKUBERNETES_DEFAULT_WORKSPACE_SIZEkubernetes runnerstringOptionalChart default
Requested size of the run workspace PVC.
KUBERNETES_DEFAULT_WORKSPACE_SIZE=20GiKUBERNETES_AFFINITY_ENABLEDkubernetes runnerbooleanOptionalChart default
Whether step pods in a run are scheduled onto the same node by default.
KUBERNETES_AFFINITY_ENABLED=truepipeline affinity_enabled
KUBERNETES_CLEANUP_FINISHED_PODSkubernetes runnerbooleanOptionalChart default
Whether finished step pods are deleted after their status is reported.
KUBERNETES_CLEANUP_FINISHED_PODS=trueNOPSAI_REGISTRY_DOCKER_CONFIG_B64docker runnerstringOptionalNone
Base64 Docker config delivered at runner bootstrap so Docker runners can build per-image RegistryAuth locally.
NOPSAI_REGISTRY_DOCKER_CONFIG_B64=<base64 docker config json>- The legacy
/v1/internal/registry-auth/dockerbroker route has been removed.
Keeps registry credentials on the runner instead of brokering them per image pull.
doc/runner-registry-auth.md
Examples
curl -s "$NOPSAI_URL/v1/system/dispatcher/runner-bootstrap-command?scopes=platform/production" \
-H "Authorization: Bearer $NOPSAI_TOKEN"How it works
The System dispatcher workspace separates compact overview metrics, a runtime-filtered table-first fleet view, route editing with the effective routing table, and install command generation. Runner detail appears below the fleet table only after an operator selects a runner.
The GitOps-owned configured route map and the live effective routing view are different things. The configured map is desired state; the effective view is derived from registered runner scopes and runtime status.
Replacing a control plane while keeping the old SERVICE_JWT_SIGNING_KEY and DISPATCHER_TLS_SECRET lets old runner definitions authenticate again unless their IDs are carried forward in ejected_runner_ids. Rotate those secrets before exposing a fresh dispatcher when old runners must not join.
Implementation evidence
services/dispatcher/internal/app/app.goDispatcher listen address and registration handling.
services/nopsai/routes.goDispatcher management and install-generation routes.

