# 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 ```bash docker compose up -d # apply config changes docker compose down # stop (registration persists in volume) ``` ⚠️ **Check for running jobs before recreating the runner.** Recreating it orphans any job in flight — Gitea marks them failed and you have to re-run: ```bash docker exec gitea-runner-dind docker ps --format '{{.Names}}' | grep -v buildkit ``` Wait until that prints nothing (`buildx_buildkit_builder-*` is a helper, not a job). ### 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).