126 lines
4.9 KiB
Markdown
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).
|