Runner Pool
ImpVMRunnerPool manages ImpVM instances for CI/CD jobs. It currently supports GitHub Actions self-hosted runners.
Sections
- Under the Hood — source-backed runner path, implemented lifecycle, and live-evidence boundary
- Scaling
- E2E Runbook
- 20-Minute Technical Presentation
How it Works
The pool controller creates and removes ImpVM objects to match runner demand. Each VM receives one JIT registration setup, then runs as an ephemeral GitHub Actions self-hosted runner. The controller removes terminal VMs and reconciles replacement capacity.
For GitHub Actions, Imp uses a GitHub App stored in a Kubernetes Secret. The operator mints one short-lived registration configuration for each runner VM. It passes that configuration directly to the guest runner at launch time. The configuration must not be placed in the VM manifest, the base image, or logs.
Runner image contract
The recommended v0.10.1 image layout keeps the operating-system base separate from the CI runner layer:
- Base image: Debian-slim with glibc, the runner user (
uid 10001), certificate and .NET runtime libraries, andCMD ["/usr/local/bin/runner"]. - Runner layer: the GitHub Actions runner under
/home/runner/actions-runnerplus/usr/local/bin/runner. Imp supplies the one-time JIT value asIMP_GITHUB_JITCONFIG; the wrapper exports it asACTIONS_RUNNER_INPUT_JITCONFIG, setsRUNNER_ALLOW_RUNASROOT=1, and executesrun.shfor one job. The wrapper does not runconfig.sh --jitconfigitself.
Published images are built for Linux amd64 by syscode-labs/imp-runner-images. Use immutable digests in a template; do not use a moving tag in a production pool. Resolve and verify the digest from the intended publication before copying it into a pool—this guide deliberately does not assert an unverified version-to-image mapping. An image publication is evidence that a layer was built and pushed, not proof that a runner has registered or completed a job in your cluster.
GitHub Actions Visibility
GitHub only sees capacity after runners register. The pool keeps minIdle pre-registered runners available for fast job pickup. Monitor both the Kubernetes side (pool status, ImpVM count) and the GitHub side (runner inventory).
Minimal Example
apiVersion: imp.dev/v1alpha1
kind: ImpVMClass
metadata:
name: runner-class
namespace: default
spec:
vcpu: 2
memoryMiB: 2048
diskGiB: 10
---
apiVersion: imp.dev/v1alpha1
kind: ImpVMTemplate
metadata:
name: gh-runner
namespace: default
spec:
classRef:
name: runner-class
image: <immutable-runner-base-image>
runnerLayer: <immutable-runner-layer-image>
---
apiVersion: imp.dev/v1alpha1
kind: ImpVMRunnerPool
metadata:
name: ci-pool
namespace: default
spec:
templateName: gh-runner
labels: [imp]
platform:
type: github-actions
scope:
org: my-org
runnerGroup: omni-runner
credentialsSecret: github-runner-app
tokenSource: github_app
scaling:
mode: polling
minIdle: 1
maxConcurrent: 5
scaleUpStep: 1
cooldownSeconds: 30
polling:
enabled: true
intervalSeconds: 30Create the github-runner-app Secret before applying this pool. The E2E runbook shows its required fields. The runner layer must provide /usr/local/bin/runner, and both images should use independently verified immutable digests.
