Skip to content

Scaling

ImpVMRunnerPool supports three scaling modes driven by spec.scaling.mode.

Modes

ModeBehavior
webhookScale from GitHub webhook demand signals
pollingScale by polling GitHub API for queued jobs
hybridUse both signals, take the higher demand

hybrid is recommended for most deployments when both demand sources are configured. For an organisation-scoped pool, polling does not currently provide organisation-wide queue depth; use webhook demand or pre-warm with minIdle.

Configuration

yaml
spec:
  scaling:
    mode: hybrid
    minIdle: 2          # always-ready runners
    maxConcurrent: 10   # hard cap on simultaneous VMs
    scaleUpStep: 2      # max new VMs per reconcile cycle
    cooldownSeconds: 60 # wait after scale-down before scaling up again

Scheduling Math

  1. Start at minIdle pre-registered runners.
  2. In hybrid mode, raise by the higher of queue depth (polling) and webhook demand.
  3. Cap by maxConcurrent.
  4. Add at most scaleUpStep VMs per reconcile.
  5. After scale-down, wait cooldownSeconds before scaling up again.

Monitor

bash
kubectl get impvmrunnerpool ci-pool -n default -o yaml
kubectl get impvm -n default -l imp.dev/pool=ci-pool

Required Secrets

For GitHub Actions, use a GitHub App secret with tokenSource: github_app. The Secret contains github-app-private-key, github-app-id, and github-app-installation-id. The operator signs a short-lived App JWT and mints installation tokens when needed.

A static token value is still accepted for compatibility, but the source marks it as deprecated for GitHub Actions pools.

Capacity Visibility

GitHub shows runner capacity only after VMs register. minIdle controls how many are pre-registered and ready for immediate job pickup.

maxConcurrent is a hard upper bound on runner VMs, not a guarantee that GitHub will assign that many jobs. Job assignment still depends on the runner group and labels selected by the workflow.