Files
act_runner/README.md
T

126 lines
4.9 KiB
Markdown

# Gitea Act Runner (DinD + cache)
Stable Gitea Actions runner for building Rust projects. Runs jobs in an isolated
Docker-in-Docker daemon with the built-in cache server enabled and multiple
parallel jobs.
## Setup on a new build machine
Requires Docker + Docker Compose.
```bash
git clone https://git.vysma.dev/nampdn/act_runner.git && cd act_runner
cp .env.example .env
# edit .env: set GITEA_RUNNER_NAME (unique per machine) and a fresh
# GITEA_RUNNER_REGISTRATION_TOKEN from Gitea -> Actions -> Runners -> Create Runner
docker compose up -d
```
Nothing else to edit — `config.yaml` ships with working defaults. Tweak
`runner.capacity` per machine if its CPU/RAM differ; that edit will show up as a
local modification in `git status`, which is expected.
Verify:
```bash
docker compose ps # both containers up, dind healthy
docker logs gitea-runner-wsl 2>&1 | tail # "declare successfully"
```
## Config
- **Parallel jobs**: `config.yaml` -> `runner.capacity` (default 4)
- **Job images**: `config.yaml` -> `runner.labels` (ubuntu-latest/22.04/24.04)
- **Cache**: `config.yaml` -> `cache.dir: "/cache"`, mounted from the
`runner-cache` volume. Docker layer cache persists separately in `dind-storage`.
> ⚠️ Leaving `cache.dir` empty makes act_runner write to `$HOME/.cache/actcache`
> — the container's **writable layer**, not a volume. Measured in production:
> 278 GB / 95 GB / 32 GB of cache sitting there across three machines, all of it
> destroyed by a single `docker compose up -d`. The two settings
> (`cache.dir` and the `runner-cache` mount) must always be changed together.
- **Runner image**: pinned by digest, not `:nightly`. A floating tag means
`docker compose pull` can recreate the container behind your back — and with it,
wipe the cache. Upgrade deliberately: change the digest, commit, then apply.
## Rust workflows
Copy `example-rust-workflow.yaml` to your repo at `.gitea/workflows/build.yaml`.
It uses `actions-rust-lang/setup-rust-toolchain` which caches `~/.cargo` and
`target/` via the runner's cache server.
## Manage
The wrapper operates only this project's Compose stack:
```bash
./runner-stack.sh up -d # start the stack
./runner-stack.sh stop # stop runner before DinD; retain containers and volumes
./runner-stack.sh down # remove containers; retain registration and caches
```
To apply an update on another existing runner, first wait for jobs to finish:
```bash
docker exec gitea-runner-dind docker ps --format '{{.Names}}'
```
Only persistent BuildKit helpers should remain. Then run:
```bash
git pull --ff-only
./runner-stack.sh stop
./runner-stack.sh up -d --force-recreate
```
Recreation loads changes in the bind-mounted runner YAML as well as Compose
settings. It retains registration and cache volumes. Keep that machine's `.env`
and intentional local capacity/label settings; resolve any pull conflicts while
retaining `runner.shutdown_timeout: 5m`. A new installation still requires the
per-machine registration setup above. Running the wrapper without arguments
prints usage and does not change the stack.
The runner waits up to five minutes for jobs to finish before cancelling them.
Compose allows six minutes before SIGKILL, leaving additional time for cleanup.
This ordering applies to Compose operations, not power loss or independently
stopping DinD. Any other clients sharing the daemon must be stopped separately
before stack maintenance.
For changes only to `config.yaml`, restart the runner to load the file:
```bash
./runner-stack.sh restart runner
```
### Network allocation
DinD allocates /24s from `10.210.0.0/16`: 256 subnet slots, including one for
its default bridge. Keep this setting when updating the daemon, and verify
that this range does not overlap routes in another machine's environment.
Host Docker has separate allocation state.
The larger pool provides headroom; interrupted jobs can still leave networks
behind. Workflow-created networks need their own teardown on success, failure
and cancellation. Inspect leftover networks inside DinD during idle maintenance;
do not schedule blanket pruning while jobs are creating their stacks.
### Housekeeping
Job images, volumes and BuildKit cache pile up inside DinD and are never reaped
automatically. Measured on one machine: 515 unused images and a 71 GB build cache.
```bash
docker exec gitea-runner-dind docker image prune -af --filter until=168h
docker exec gitea-runner-dind docker builder prune -f --keep-storage 20GB
# volume prune only removes *anonymous* volumes; task volumes are named:
for v in $(docker exec gitea-runner-dind docker volume ls -q | grep '^GITEA-ACTIONS-TASK'); do
docker exec gitea-runner-dind docker volume rm "$v" 2>/dev/null
done
```
Keep `act-toolcache` and don't wipe the BuildKit cache outright — cap it instead.
> Each machine needs a unique `GITEA_RUNNER_NAME` and its own registration token.
> Run `docker compose down -v` to fully reset (drops registration + caches).