GitHub Actions Tutorial — Ephemeral Runners
Ephemeral Runners
Ephemeral runners process a single job and then automatically de-register. Each job gets a clean environment — no leftover files, credentials, or state from previous runs.
Why Ephemeral?
| Persistent Runner | Ephemeral Runner |
|---|---|
| Keeps state between jobs | Clean slate every job |
| Risk of credential leaks | No credentials persist |
| Disk fills over time | Fresh workspace every time |
| Must clean up manually | Automatic cleanup |
| Faster (no setup) | Slightly slower (re-setup) |
Configuring Ephemeral Mode
At Registration
./config.sh --url https://github.com/my-org/my-repo \
--token TOKEN \
--ephemeral
The --ephemeral flag tells the runner to process one job and then exit.
How It Works
1. Runner starts → registers with GitHub
2. Picks up one queued job
3. Executes the job
4. De-registers → exits
5. Orchestrator restarts a new runner instance
Ephemeral Runners with ARC
ARC runners are ephemeral by default — each Kubernetes pod runs one job:
helm install arc-runner-set \
--namespace arc-runners \
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
# Ephemeral by default in ARC
Ephemeral Runners with VMs
Use cloud VM auto-scaling to create ephemeral runners:
AWS Auto Scaling Group
1. Launch Template with runner setup script
2. Auto Scaling Group: min=0, max=10
3. Lambda function listens for workflow_job webhooks
4. Scales up on 'queued', scales down on 'completed'
User Data Script (AWS EC2)
#!/bin/bash
# Configure and run ephemeral runner
cd /home/runner/actions-runner
./config.sh --url https://github.com/my-org \
--token "$TOKEN" \
--ephemeral \
--unattended
./run.sh
# After job completes, runner exits
# Auto Scaling Group terminates the instance
shutdown -h now
JIT (Just-In-Time) Runners
GitHub also supports JIT runner configuration via the API — generate a one-time config for a specific job:
# API call returns a JIT config token
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
https://api.github.com/repos/OWNER/REPO/actions/runners/generate-jitconfig \
-d '{"name":"jit-runner","runner_group_id":1,"labels":["self-hosted","linux"]}'
JIT runners are always ephemeral — they’re configured for exactly one job.
Common Mistakes
| Mistake | Fix |
|---|---|
| Runner doesn’t restart after job | You need an orchestrator (systemd, K8s, ASG) to restart it |
| State persists between jobs | Ensure --ephemeral flag is set |
| Slow startup | Pre-bake common tools into the runner image |
| Registration token expires | Generate fresh tokens for each runner instance |
Quick Reference
| Concept | Detail |
|---|---|
| Flag | --ephemeral during config.sh |
| Behavior | One job → exit |
| ARC | Ephemeral by default |
| VMs | Combine with auto-scaling groups |
| JIT | API-generated one-time config |
| Benefit | Clean environment, no state leaks |
← Previous: Autoscaling (ARC)
Next: Security Considerations →