forgejo: record why the runner is on vps2, rather than leaving a contradiction #153

Merged
admin_emi merged 1 commit from docs/runner-vps2-decision into dev 2026-08-01 17:00:37 +00:00

View file

@ -177,14 +177,48 @@ parallel, and even capacity 3 (an earlier, undocumented hand-tune) leaves
`build-backend`/`build-frontend`/`validate-observability` queued behind `build-backend`/`build-frontend`/`validate-observability` queued behind
those three before they get a slot. those three before they get a slot.
**Adding more runner capacity should mean raising this number, or adding a **This paragraph used to say a runner must never go on vps2. That was reversed
second runner alongside it — not putting a runner on prod or beta (vps2).** deliberately on 2026-08-01, and the reasoning is worth keeping rather than
`container.docker_host: automount` gives job containers the *host's* Docker quietly deleting.**
socket; on vps2 that would mean any CI job has root-equivalent access to both
the prod and beta stacks running there. An earlier revision of this stack The original objection stands on its merits: `container.docker_host: automount`
actually ran the runner as a Swarm-hosted container on the box Forgejo was gives job containers the *host's* Docker socket, so a runner on vps2 means any
pinned to and was deliberately reverted for this same class of reason — see CI job has root-equivalent access to both the prod and beta stacks running
the note at the top of `docker-stack.yml`. there. An earlier revision of this stack ran the runner as a Swarm-hosted
container on the Forgejo node and was reverted for the same class of reason.
What changed is that the alternative turned out to be worse. The desktop was
the estate's **only** registered runner, and when it went offline on
2026-07-31 nothing merged, nothing deployed, and the nightly backup did not
fire for 21 hours — on a repo where every branch is protected and every change
is a PR, a single absent runner freezes the whole estate. Availability of CI
is not a convenience here; it is what the backup and the deploy path both
hang off.
So the runner on vps2 (`runner-vps2/`) is a considered trade, not an
oversight, and it is bounded rather than assumed benign:
- `capacity: 1` — one job at a time, so a CI burst cannot contend with
`thermograph_web` for the box's six cores.
- `--cpus=2 --memory=4g` on job containers, set in `container.options`. Job
containers are siblings of the runner rather than children, so the runner's
own compose limits do not reach them; that option is the only lever that
does.
- `valid_volumes: []` — a job cannot bind-mount a host path, which is the
difference between "a job can read `/etc/thermograph.env`" and "a job
cannot", on the box where that file is prod's.
- The compose project joins no `thermograph` network.
Be honest about what that buys: it is defence against **accident**, not
against a hostile workflow author. Forgejo's own database on vps1 already
stores `VPS2_SSH_KEY`, which is root on vps2, so the material was already
reachable — what changed is that it is now reachable by a *job* rather than
only at rest. On a two-person estate where both people can already SSH to that
box as root, that is the honest boundary.
**If you are adding capacity rather than redundancy, raise `capacity` or add a
runner on a box that hosts nothing.** The vps2 runner exists so that CI has a
second home, not because prod is a good place to run CI.
## Custom CI job image (`ci-runner/`) ## Custom CI job image (`ci-runner/`)