GitHub Actions Tutorial — Autoscaling (ARC)
1 minute read
Autoscaling with Actions Runner Controller (ARC)
Actions Runner Controller (ARC) runs self-hosted runners as Kubernetes pods. It automatically scales the number of runners up and down based on workflow demand — no idle machines burning money.
Why ARC?
| Challenge |
ARC Solution |
| Runners sit idle between jobs |
Scales to zero when no jobs are queued |
| Manual capacity planning |
Autoscales based on pending jobs |
| Stale runner environments |
Ephemeral pods — fresh for every job |
| Runner management overhead |
Kubernetes handles scheduling and lifecycle |
Architecture
GitHub.com
│
├── Webhook: workflow_job queued
│
▼
ARC Controller (Kubernetes)
│
├── Watches for pending workflow jobs
├── Creates runner pods on demand
│
▼
Runner Pod (ephemeral)
├── Picks up the job
├── Executes workflow steps
└── Terminates after job completes
Installation with Helm
Prerequisites
- Kubernetes cluster (EKS, GKE, AKS, or local)
- Helm 3
- GitHub App or PAT for authentication
Install ARC
# Add the Helm chart
helm install arc \
--namespace arc-systems \
--create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
Deploy a Runner Scale Set
helm install arc-runner-set \
--namespace arc-runners \
--create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set \
--set githubConfigUrl="https://github.com/my-org" \
--set githubConfigSecret.github_token="ghp_xxxxx" \
--set minRunners=0 \
--set maxRunners=10
Use in Workflows
jobs:
build:
runs-on: arc-runner-set # matches the Helm release name
steps:
- uses: actions/checkout@v4
- run: echo "Running on ARC!"
Scaling Configuration
| Parameter |
Default |
Purpose |
minRunners |
0 |
Minimum idle runners |
maxRunners |
5 |
Maximum concurrent runners |
- minRunners: 0 — scales to zero between jobs (cost-efficient)
- minRunners: 1 — always one runner warm (faster first-job startup)
Authentication Methods
| Method |
Scope |
Recommendation |
| GitHub App |
Org/Repo |
✅ Recommended (fine-grained permissions) |
| PAT (classic) |
User |
⚠️ Works but broad scope |
| PAT (fine-grained) |
Repo |
✅ Good for single-repo |
Common Mistakes
| Mistake |
Fix |
| Pods not starting |
Check Kubernetes events: kubectl describe pod |
| Runner not picking up jobs |
Verify runs-on: label matches the scale set name |
| Authentication errors |
Ensure token/app has correct permissions |
| Runners not scaling down |
Check ARC controller logs for scaling decisions |
Quick Reference
| Concept |
Detail |
| What |
Self-hosted runners on Kubernetes |
| Install |
Helm chart from ghcr.io/actions/... |
| Scale |
minRunners and maxRunners |
| Auth |
GitHub App (recommended) or PAT |
| Use |
runs-on: <scale-set-name> |
| Ephemeral |
Each pod runs one job, then terminates |
← Previous: Runner Groups & Labels
Next: Ephemeral Runners →