- Add deployment decision matrix with scenario-based recommendations - Add runner offline diagnostic procedure (logs→network→gh CLI→fixes) - Add runner lifecycle hooks (ACTIONS_RUNNER_HOOK_JOB_STARTED/COMPLETED) - Add Dependabot runner integration (allow toggle, runner group API flag) - Bump v1.0.1 → v1.0.2
5.8 KiB
Deployment Approaches
Four primary approaches to deploying self-hosted runners.
1. systemd Service (Linux)
Simplest approach. Download the runner binary, configure, install as a service.
mkdir actions-runner && cd actions-runner
curl -o runner.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.322.0/actions-runner-linux-x64-2.322.0.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/org/repo --token <token>
sudo ./svc.sh install
sudo ./svc.sh start
Pros: Minimal dependencies, full control, direct filesystem access Cons: Manual updates, no built-in lifecycle management, state lives on the host
2. Docker Container (myoung34/github-runner)
Ubuntu 20.04-based image wrapping the runner binary with Docker-specific lifecycle management.
services:
runner:
image: myoung34/github-runner:latest
container_name: runner
restart: unless-stopped
environment:
- RUNNER_NAME=my-runner
- RUNNER_SCOPE=org
- ORG_NAME=myorg
- ACCESS_TOKEN=ghp_...
- RUNNER_GROUP=self-hosted
- LABELS=self-hosted,linux,x64
- DISABLE_AUTO_UPDATE=1
- EPHEMERAL=false
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- runner-data:/runner
networks:
- traefik
volumes:
runner-data:
networks:
traefik:
external: true
Pros: Container isolation, named volume for credentials, Docker socket for DinD builds, easy multi-replica Cons: Cannot see host filesystem paths, Ubuntu 20.04 base (Python 3.8), needs Docker socket for builds
Critical environment variables:
| Variable | Purpose | Notes |
|---|---|---|
ACCESS_TOKEN |
GitHub PAT for registration | Use this, NOT RUNNER_TOKEN |
RUNNER_SCOPE |
org or repo |
Determines registration endpoint |
ORG_NAME |
GitHub org | Required for org scope |
REPO_URL |
Full repo URL | Required for repo scope |
RUNNER_GROUP |
Target group | Fails if group doesn't exist |
LABELS |
Comma-separated | Job routing |
EPHEMERAL |
false or true |
Use string, not 0 |
DISABLE_AUTO_UPDATE |
1 |
Docker handles version management |
RUNNER_WORKDIR |
/runner/work |
Job working directory |
# Use .env file for the token
echo "ACCESS_TOKEN=ghp_..." > .env
# In docker-compose.yml: ${ACCESS_TOKEN} or inline
3. Actions Runner Controller (ARC) — Kubernetes
GitHub's reference implementation — a Kubernetes operator that orchestrates runner scale sets.
Architecture:
- Controller manager deploys in specified namespace
- AutoScalingRunnerSet resource registers runner scale set with GitHub API
- Runner ScaleSet Listener establishes HTTPS long-poll connection
- When a job arrives, listener patches EphemeralRunnerSet with desired replica count
- EphemeralRunner Controller requests JIT tokens and creates runner pods
- Runner pod executes job, deregisters, pod is deleted
Quickstart:
# Install the controller
helm install arc-controller \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller \
--namespace arc-system --create-namespace
# Deploy a runner scale set
helm install arc-runner-set \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set \
--namespace arc-runners --create-namespace \
--values values.yaml
Container modes:
- Docker-in-Docker (dind): Runner pod runs Docker inside — heavier, for workflows needing Docker actions
- Kubernetes mode: Steps run as individual pods — lighter, cleaner isolation
- Default: Runner binary runs directly in container
Required CRDs:
AutoScalingRunnerSetEphemeralRunnerSetRunnerScaleSetListener
4. GitHub Actions Runner Scale Set Client
Standalone Go module for building custom autoscaling outside Kubernetes. Handles GitHub API interactions while you handle infrastructure provisioning.
Use case: Platform teams who need custom autoscaling across VMs, containers, on-prem, or cloud. Supports Windows, Linux, macOS.
Key properties:
- Orchestrates GitHub API interactions for scale set registration
- Leaves infrastructure provisioning to you
- Multiple labels for flexible job routing
- Real-time telemetry for job execution
- Extensible — customize for specific requirements
Note: This is NOT a replacement for ARC. ARC remains the reference Kubernetes implementation. The Scale Set Client is for non-Kubernetes environments.
Repository: actions/scaleset on GitHub
Decision Matrix: Which Approach to Choose
| Scenario | Recommended | Why |
|---|---|---|
| Single machine, simple CI, <10 runs/day | systemd | Minimal dependencies, full filesystem access, no Docker needed |
| Small team (3-10), multiple servers, ~10-100 runs/day | Docker | Container isolation, easy management, restart-on-failure, DinD for builds |
| 10+ devs, growing CI volume, existing K8s cluster | ARC | Production autoscaling, K8s-native, JIT tokens, clean per-job isolation |
| Platform team, non-K8s infra, custom provisioning | Scale Set Client | Full control over provisioning, VM/hybrid/multi-platform, customized scaling logic |
Decision flow:
- Do you have a Kubernetes cluster you already maintain? → ARC
- No K8s but need isolation and container management? → Docker
- Only 1 machine, low volume, no containers needed? → systemd
- Platform team with custom infrastructure and non-K8s scale requirements? → Scale Set Client
Deployment Comparison
| Approach | Complexity | Autoscaling | Security | Best For |
|---|---|---|---|---|
| systemd | Low | Manual | Low | Single machine, simple CI |
| Docker | Medium | Manual replicas | Medium | Small team, homelab |
| ARC (K8s) | High | Yes (Kubernetes) | High | Teams with K8s expertise |
| Scale Set Client | High | Yes (custom) | High | Platform teams, non-K8s |