-
Notifications
You must be signed in to change notification settings - Fork 0
Usage
This page is the operational walkthrough. Start with the supported host you already have:
- Tart on Apple Silicon macOS
- WSL2 on Windows
- Docker-DinD on a Docker-capable host
Install the host tools you need:
| Required for | Tool |
|---|---|
| All hosts | Go 1.22 or newer, Git |
| macOS provider | Tart |
| Windows provider | WSL2 |
| Docker-DinD provider | Docker Engine, OrbStack, or Docker Desktop with privileged container support |
| Optional Docker registry mirrors | A running mirror service on the host, LAN, intranet, or cloud registry cache |
| Runner registration | GitHub App with organization self-hosted runner read/write permission |
Packer, GitHub CLI, and sshpass are not required.
Set up the GitHub App before registering runners. The image build command can run without GitHub credentials, but pool verify --register-only, pool up, status, and GitHub cleanup need the app settings. See GitHub App Setup.
Copy one example config into .local/config.yml, then edit the GitHub App fields and any labels you want to expose to workflows.
| Host and image | Example config |
|---|---|
| macOS Tart, runner-only | configs/tart.example.yml |
| macOS Tart, web/E2E with Rosetta amd64 Docker support | configs/tart.web-e2e.example.yml |
| Windows WSL2, runner-only | configs/wsl.example.yml |
| Windows WSL2, web/E2E | configs/wsl.web-e2e.example.yml |
| Docker-DinD, runner-only | configs/docker-dind.example.yml |
| Docker-DinD, web/E2E | configs/docker-dind.web-e2e.example.yml |
macOS:
mkdir -p .local
cp configs/tart.example.yml .local/config.ymlWindows:
New-Item -ItemType Directory -Force .local
Copy-Item configs/wsl.example.yml .local/config.ymlDocker-DinD:
mkdir -p .local
cp configs/docker-dind.example.yml .local/config.ymlEPAR looks for config in this order:
--config <path>EPAR_CONFIG./.local/config.yml~/.config/ephemeral-action-runner/config.yml
Tracked configs are examples only. Keep real app IDs and private key paths in an ignored config file.
If repeated jobs spend time pulling the same Docker Hub images into fresh runner Docker daemons, configure mirrors in your ignored local config:
docker:
registryMirrors:
- http://host.docker.internal:5050This is optional. Without it, EPAR behaves normally and pulls directly from registries. Mirror benefits vary by workflow and mainly affect Docker image pull time; they do not make application startup, volume sync, health checks, browser tests, or CPU-bound work faster.
EPAR only configures runner-side Docker daemons; it does not run or secure the mirror service. Docker Engine, Docker Desktop, or OrbStack can run a local registry:2 pull-through cache on the EPAR host, or you can use a mirror reachable on the LAN/intranet. For private images, keep using docker login inside the workflow unless your mirror is deliberately configured and secured with upstream credentials. See Docker Registry Mirrors.
go build -o ./bin/ephemeral-action-runner ./cmd/ephemeral-action-runnerUse ./bin/ephemeral-action-runner in the examples below, or put bin on PATH.
Skip this section for Tart and Docker-DinD.
The WSL provider builds reusable rootfs tar images. Create the clean Ubuntu 24.04 source tar once:
New-Item -ItemType Directory -Force work/images
wsl --install -d Ubuntu-24.04 --no-launch
wsl --export Ubuntu-24.04 work/images/ubuntu-24.04-clean.rootfs.tarAfter that, EPAR imports disposable temporary distros for image builds and pool instances.
Runner-only Tart and WSL images do not need the upstream actions/runner-images checkout:
./bin/ephemeral-action-runner image build --replaceIf provider.type: docker-dind, or if image.customInstallScripts includes EPAR's Docker/browser or web/E2E scripts, update the pinned upstream checkout first:
./bin/ephemeral-action-runner image update-upstream
./bin/ephemeral-action-runner image build --replaceThe Tart web/E2E example sets provider.rosettaTag: rosetta. Tart builds with that option start with tart run --rosetta rosetta, install Rosetta guest support, and validate that Docker can run a linux/amd64 Alpine container returning x86_64.
Tart output is a local Tart image name, such as epar-ubuntu-24-arm64. Confirm it with:
tart listWSL output is a rootfs tar path, such as:
work/images/epar-ubuntu-24-wsl.tar
Docker-DinD output is a Docker image tag, such as epar-docker-dind-ubuntu-24. Confirm it with:
docker image ls epar-docker-dind-ubuntu-24Build logs are written under work/logs.
The public default image is runner-only. Add tooling through image.customInstallScripts:
image:
customInstallScripts:
- scripts/guest/ubuntu/install-web-e2e.sh
- examples/custom-install/install-extra-apt-tools.shScripts run as root during image build, after the GitHub Actions runner is installed and before validation/finalization. See Image Build for the full layering model and custom script guidance.
For a local runtime check without GitHub registration:
./bin/ephemeral-action-runner pool verify --instances 1 --cleanupFor a full registration check:
./bin/ephemeral-action-runner pool verify --instances 2 --register-only --cleanupHealthy output should show each generated instance name moving through:
- clone
- start
- runtime validation
- GitHub online/idle, when registration is enabled
- cleanup
Runtime validation always checks the base runner files and runner user. Images with optional feature markers also validate those features:
- Docker/browser images validate Docker, Compose v2, Buildx,
hello-world, and a headless browser. - Docker-DinD images validate the private inner Docker daemon inside each runner container.
- Tart Rosetta images validate
docker run --platform linux/amd64 alpine:3.20and expectuname -mto returnx86_64. - Web/E2E images also validate
node,npm,zip,unzip,tar,rsync, andmysql.
When docker.registryMirrors is configured, EPAR applies the mirror configuration before runtime validation.
If a Docker-DinD workflow depends on amd64-only images while the host is ARM64, validate host emulation inside a running EPAR instance:
docker exec <epar-instance> docker run --rm --platform linux/amd64 alpine:3.20 uname -mThe expected output is x86_64.
./bin/ephemeral-action-runner pool up --instances 2pool up keeps the requested number of runners online. Each GitHub ephemeral runner exits after one job. EPAR then retires that instance and creates a fresh replacement.
Stop the supervisor with Ctrl-C. By default, EPAR cleans up active instances and matching GitHub runner records before it exits.
On macOS, see macOS Startup for an example .command file that waits for Docker and starts pool up after login.
Use these flags only for debugging:
-
--keep-on-exit: leave instances running when the supervisor exits. -
--replace-completed=false: do not create replacements after completed jobs.
./bin/ephemeral-action-runner status
./bin/ephemeral-action-runner cleanupCleanup only touches local instances and GitHub runners whose names match pool.namePrefix.
Use provider-specific labels in workflows. For the Tart web/E2E Rosetta image, target the existing web/E2E label plus the Rosetta label when the job needs amd64 Docker images:
runs-on: [self-hosted, linux, ARM64, epar-tart-ubuntu-24.04-web-e2e, epar-tart-rosetta-amd64]For Docker-DinD web/E2E images, target the Docker-DinD label:
runs-on: [self-hosted, linux, ARM64, epar-docker-dind-ubuntu-24.04-web-e2e]When that Docker-DinD runner is used for amd64-only runtime images, keep the workflow's Docker platform explicit, for example DOCKER_PLATFORM=linux/amd64 or the equivalent variable used by your compose scripts, and verify the host runtime supports amd64 emulation as described above.
Do not use ubuntu-latest for these self-hosted runners.
Use --dry-run to inspect provider command construction without mutating local instances:
./bin/ephemeral-action-runner pool verify --dry-run --instances 2Generated from the main repository docs at b721d85. Edit README.md and docs/; the wiki copy is overwritten by automation.