English | 中文
This repository provides scripts and tools for creating, managing, and registering GitHub self-hosted runners in Docker containers. Unlike installing the official GitHub self-hosted runner directly on the host, this approach encapsulates runners in Docker containers with the following benefits:
- Environment Isolation: Each runner runs in an isolated container, avoiding dependency conflicts
- Easy Management: Batch management of multiple runner instances via Docker Compose
- Fast Deployment: Supports custom images with pre-installed toolchains
- Multi-Org Support: Multiple containers can run on the same host, registering to different organizations
- Batch management of multiple runner containers using Docker Compose
- Support for organization-level and repository-level runners (controlled by
REPOvariable) - Per-runner configuration for labels, devices, groups, volumes, environment variables, and commands
- Automatic custom image rebuild when
Dockerfilechanges - Cached registration tokens to reduce GitHub API requests
- Full lifecycle commands:
init,add,compose,register,start,stop,restart,log,list,rm,purge,image
- Docker and Docker Compose installed on the host
- GitHub Classic Personal Access Token (
GH_PAT) with appropriate permissions (org admin for organization-level, repo admin for repository-level)
# 1. Make the script executable
chmod +x runner.sh
# 2. Generate and start runners
./runner.sh init [-n N]| Command | Description |
|---|---|
./runner.sh init [-n N] |
Generate and start N runners |
./runner.sh add [-n N] |
Append N new runners after the existing runner indexes |
./runner.sh compose |
Regenerate compose file with existing runners |
./runner.sh register [runner-<id> ...] |
Register specified instances; without arguments, registers all unconfigured instances |
./runner.sh start/stop/restart [runner-<id> ...] |
Start/stop/restart containers |
./runner.sh log runner-<id> |
Follow instance logs |
./runner.sh ps |
Show container status |
./runner.sh list |
Show local container status and GitHub registration status |
./runner.sh rm [runner-<id> ...] [-y] |
Unregister and remove containers; -y skips confirmation |
./runner.sh purge [-y] |
Remove containers and generated files (docker-compose.yml, caches, etc.) |
./runner.sh image |
Rebuild the custom runner image |
The default prefix automatically includes ORG (and REPO if set), formatted as <hostname>-<org>-runner-N or <hostname>-<org>-<repo>-runner-N to avoid naming conflicts when multiple orgs/repos run on the same host. Override with RUNNER_NAME_PREFIX.
All runners use the same naming format, ${RUNNER_NAME_PREFIX}runner-N. The -n option controls the total number of runners. Use the default RUNNER_* variables for all runners, and append an index such as _1 or _2 to override one runner.
| Variable | Default | Description |
|---|---|---|
RUNNER_LABELS |
intel |
Labels used when registering runners |
RUNNER_DEVICES |
/dev/loop-control,/dev/loop0,/dev/loop1,/dev/loop2,/dev/loop3,/dev/kvm |
Comma-separated device mappings; entries without : are mapped to the same path in the container |
RUNNER_GROUP_ADD |
dialout |
Comma-separated extra groups added to runner containers |
RUNNER_VOLUMES |
empty | Semicolon-separated extra volume mounts |
RUNNER_ENV |
empty | Semicolon-separated KEY=VALUE environment variables |
RUNNER_COMMAND |
/home/runner/run.sh |
Command executed by runners |
Example per-runner overrides:
RUNNER_LABELS_2=board,phytiumpi,arm64
RUNNER_DEVICES_2=/dev/kvm,/dev/ttyUSB0:/dev/ttyUSB0
RUNNER_ENV_2='BOARD_NAME=phytiumpi;SERIAL=/dev/ttyUSB0'- Custom Image: If a
Dockerfileexists, the script will rebuildRUNNER_CUSTOM_IMAGEbased on hash changes - Token Cache: Registration tokens are cached in
.reg_token.cache, configure TTL viaREG_TOKEN_CACHE_TTL(seconds)
# 1. Fork and create a branch
git checkout -b feat/my-change
# 2. Make changes and validate syntax
bash -n runner.sh
# 3. Submit a PR describing the changes and test stepsNotes:
- Do not commit files containing
GH_PATor other sensitive information - Document new dependencies in README and provide fallback options where possible
- Keep scripts compatible with Bash