65 lines
4.0 KiB
Markdown
65 lines
4.0 KiB
Markdown
# CI-Runner auf node1 + CI-Pipeline-Overhaul (2026-06-28)
|
|
|
|
> Operativer Record der CI-Umstellung. Runner-Host-Themen gehören mittelfristig auch nach
|
|
> `infra/LESSONS.md` (Infra-Repo, Akeshan-Domain) — hier dokumentiert, weil die
|
|
> `.gitea/workflows/`-Änderungen in diesem Repo liegen.
|
|
|
|
## Warum: Homeserver OOMte unter paralleler CI
|
|
Der geteilte Homeserver (32 GB RAM, neben anderen Diensten ~17 GB belegt) ist bei paralleler
|
|
CI wiederholt abgestürzt: parallele Jobs spikten den RAM auf 30+/32 GB, CPU auf 100%, der
|
|
Linux-OOM-Killer riss den größten Job → Crash-Recover-Schleife (Runner grabbte sofort den
|
|
nächsten Job). Parallelisierung auf der geteilten Box war der falsche Hebel.
|
|
|
|
## Lösung: node1 als dedizierter CI-Runner
|
|
node1 (`176.9.111.179`, eigener Hetzner-Dedi mit self-hosted Sentry, **20 Kerne / 62 GB**)
|
|
ist Mesh-Peer und erreicht Gitea über `10.42.0.2`. Gitea-Server bleibt, wo er ist — nur die
|
|
Runner-Last zieht um.
|
|
|
|
- Compose: `/opt/stacks/gitea-ci-runner/docker-compose.yml` (`network_mode: host`,
|
|
`--add-host git.tool-ctrl.de:10.42.0.2`, `CONFIG_FILE=/data/config.yaml`).
|
|
- Config: `/srv/data/gitea-ci-runner/config.yaml` (capacity, labels, cache.dir).
|
|
- Homeserver-Runner steht auf `restart=no` (aus, kein Auto-Restart, keine OOM-Schleife).
|
|
|
|
### act_runner-Footguns (alle real getroffen)
|
|
| Symptom | Ursache | Fix |
|
|
|---|---|---|
|
|
| `runner.capacity` wird ignoriert | run.sh überschreibt den compose-`command`, läuft ohne `--config` | env `CONFIG_FILE=/data/config.yaml` setzen |
|
|
| "no matching runner online with label toolctrl-ci" | leere `runner.labels` → KEIN Fallback auf `.runner` | Labels EXPLIZIT in config.yaml |
|
|
| Daemon "token is empty" trotz erfolgreicher Registrierung | `act_runner register` schrieb `.runner` ins Container-CWD → bei `--rm` weg | `docker run -w /data ...` beim Register |
|
|
| Register "instance address is empty" | run.sh ignoriert CLI-Args, nutzt leeres `GITEA_INSTANCE_URL` | `--entrypoint act_runner` umgeht run.sh |
|
|
| pnpm-Store-Cache greift nie (Cache-Dir 12K) | `cache.dir` default ephemer im Container, Restarts wischen ihn | `cache.dir: /data/actcache` (gemountet) |
|
|
|
|
## Capacity-Findings (empirisch gemessen)
|
|
| Setup | Wallclock | RAM-Peak frei | Notiz |
|
|
|---|---|---|---|
|
|
| cap 4, docker-smoke auf Tail | ~10m | 35 GB | |
|
|
| cap 6 | ~8m | 23-25 GB | |
|
|
| cap 6 + docker-smoke parallel | ~7m35s | 23 GB | |
|
|
| **cap 8 + docker-smoke parallel** | **~6m53s** | **25 GB** | Sweet-Spot |
|
|
|
|
**cap 8 ist schneller als cap 6** trotz mehr Contention: Install/Netzwerk/Docker sind
|
|
I/O-bound, die 20 Kerne tragen 8 Jobs; die Queueing-Reduktion schlägt die Mehr-Contention.
|
|
cap >8 bringt nichts (Kerne saturiert). Reise gesamt: **~32m → ~6m53s**.
|
|
|
|
## Pipeline-Änderungen (.gitea/workflows/)
|
|
- **docker-smoke `needs` entfernt** → läuft parallel zur Quality-Phase (baut Images aus
|
|
Source, keine Cross-Job-Artefakt-Abhängigkeit), raus aus dem kritischen Tail.
|
|
- **Sentry-Release-Jobs aus ci.yml entfernt** (ci.yml läuft nur auf `pull_request`; ein
|
|
PR-Build wird nirgends deployed → die Release/Sourcemaps mappen auf keine Deployment).
|
|
Release passiert in `deploy.yml` (push→main / promote).
|
|
|
|
## Install-Diagnose (warum KEIN Deps-Image)
|
|
Gemessen: Install = **~43s Download + ~15s Link** (warmer Store). Die ~2-min-Annahme war zu
|
|
hoch. Ein Deps-Image würde nur die 15s Link sparen → verworfen. Der Hebel war der **kalte
|
|
Store** (Cache persistierte nicht) → mit `cache.dir` gefixt.
|
|
|
|
## Offene Punkte
|
|
- **Sourcemaps im Deploy:** web nutzt `@sentry/vite-plugin` (lädt Sourcemaps beim Build hoch,
|
|
wenn `SENTRY_AUTH_TOKEN` gesetzt). To-do: Token als BuildKit-`--secret` an den
|
|
`web-build`-Dockerfile-Stage durchreichen (NICHT build-arg → kein Leak) +
|
|
`SENTRY_PROJECT=web` explizit (Default ist alter Slug `hivegrid-web`). Nur auf echtem
|
|
Deploy testbar → bis Sentry-Go-Live aufgeschoben.
|
|
- **Persistenter Store-Cache:** `cache.dir` gesetzt + befüllt (2,9 GB), aber Hit-Gewinn bei
|
|
cap 8 noch ungemessen (Per-Job-Restore-I/O könnte Download-Gewinn auffressen → ggf. auf
|
|
geteilten gemounteten Store umstellen statt actions/cache).
|