rebreak-monorepo/docs/superpowers/specs/2026-06-18-self-hosted-github-runner-design.md

243 lines
9.2 KiB
Markdown

# Self-Hosted GitHub Actions Runner für rebreak-monorepo
**Datum:** 2026-06-18
**Status:** Genehmigt — bereit für Implementierungsplanung
**Autor:** Kimi Code (Brainstorming-Session)
**Ziel:** GitHub-Actions-Buildkosten eliminieren, indem Backend- und Admin-Builds auf den bereits vorhandenen Hetzner-Server `api.trucko.org` (128.140.47.53) verlagert werden.
---
## 1. Zusammenfassung
Derzeit laufen Backend- und Admin-Builds auf kostenpflichtigen GitHub-gehosteten Runnern (`ubuntu-latest`). Bei einem privaten Repository führt das bei hoher Push-Frequenz zu Kosten von über 200 €/Monat.
Dieses Design schlägt vor, einen **self-hosted GitHub Actions Runner** auf dem bereits vorhandenen, aktuell ungenutzten Hetzner-Server `api.trucko.org` (128.140.47.53, 8 GB RAM) zu betreiben. Der Code-Hosting-Aspekt bleibt vollständig auf GitHub; nur die Build- und Deploy-Ausführung wird auf die eigene Infrastruktur verlagert.
Das Runner-Label `raynis-builder` ist bewusst generisch gewählt, damit später weitere Raynis-Apps (Mutterfirma von ReBreak) denselben Runner nutzen können.
---
## 2. Kontext & Ausgangslage
### Aktueller Flow
```
local dev → push to main
GitHub Actions (ubuntu-latest)
Build Backend / Admin
Upload Artifact
Deploy-Job (ubuntu-latest)
SCP + SSH zu staging.rebreak.org
deploy-from-artifact.sh
```
### Bestehende Komponenten (werden wiederverwendet)
- `.github/workflows/deploy-staging.yml`
- `.github/workflows/deploy-admin-staging.yml`
- `scripts/deploy-from-artifact.sh`
- `scripts/deploy-admin-from-artifact.sh`
- `ecosystem.config.js` auf `staging.rebreak.org`
### Probleme mit dem aktuellen Setup
- GitHub Actions Minuten kosten bei privatem Repo über 200 €/Monat.
- Keine Notwendigkeit für die ursprüngliche Entscheidung, Builds auf GitHub laufen zu lassen (Server-OOM auf CX23) — `api.trucko.org` hat 8 GB RAM.
---
## 3. Ziele
1. **Kosten eliminieren:** Keine kostenpflichtigen GitHub Actions Minuten mehr für Backend-/Admin-Builds.
2. **Minimaler Änderungsaufwand:** Bestehende Workflows und Deploy-Scripts bleiben weitgehend erhalten.
3. **Sicherheit:** Self-hosted Runner wird nicht für Pull Requests von Forks genutzt.
4. **Zuverlässigkeit:** Concurrency-Group, Health-Check und atomic deploy bleiben erhalten.
## 4. Nicht-Ziele
- Kein Wechsel des Code-Hostings (GitHub bleibt).
- Kein Ersatz für Windows- oder iOS-Builds (diese bleiben bei GitHub Actions oder werden lokal gebaut).
- Keine Einführung zusätzlicher CI-Tools wie Gitea, GitLab oder Woodpecker.
- Keine Änderung an der Production-Infrastruktur auf `staging.rebreak.org` über das Nötige hinaus.
---
## 5. Architektur
```
GitHub Push (main)
GitHub Actions Workflow
Self-hosted Runner auf api.trucko.org
Checkout → pnpm install → pnpm build → tar artifact
SCP artifact zu staging.rebreak.org
SSH: bash /srv/rebreak/scripts/deploy-from-artifact.sh
Atomic swap .output-staging + pm2 restart + health-check
```
### Komponenten
| Komponente | Ort | Verantwortung |
|---|---|---|
| GitHub Repository | GitHub Cloud | Code-Hosting, Workflow-Definitionen |
| GitHub Actions Runner | `api.trucko.org` | Workflow-Ausführung, Build, Deploy-Trigger |
| Build-Umgebung | `api.trucko.org` | `pnpm install`, `pnpm build`, Artifact-Erstellung |
| Production-Server | `staging.rebreak.org` | Artifact entpacken, Migrationen, PM2-Restart |
| Deploy-Script | `staging.rebreak.org` | `scripts/deploy-from-artifact.sh` / `deploy-admin-from-artifact.sh` |
---
## 6. Datenfluss (detailliert)
### 6.1 Backend-Deploy
1. Push auf `main` triggert `.github/workflows/deploy-staging.yml`.
2. Workflow-Job `build` läuft auf `runs-on: self-hosted` (Runner auf `api.trucko.org`).
3. Runner checkt Repo mit `actions/checkout@v4` aus.
4. `pnpm install --frozen-lockfile` wird ausgeführt.
5. `cd backend && pnpm build` erzeugt `backend/.output`.
6. Artifact wird gepackt: `tar czf backend-output.tar.gz -C backend/.output .`.
7. Artifact wird per SCP auf `staging.rebreak.org:/srv/rebreak/backend/.output-incoming.tar.gz` kopiert.
8. `imap-idle/` wird per SCP synchronisiert.
9. Runner führt per SSH `bash /srv/rebreak/scripts/deploy-from-artifact.sh` aus.
10. Server entpackt Artifact atomisch, führt ggf. Prisma-Migrationen aus und restartet `rebreak-staging`.
11. Health-Check gegen `https://staging.rebreak.org/api/auth/me` prüft Erreichbarkeit.
### 6.2 Admin-Deploy
- Analog zu Backend über `.github/workflows/deploy-admin-staging.yml`.
- Ziel: `staging.rebreak.org:/srv/rebreak/apps/admin/.output-incoming.tar.gz`.
- Script: `scripts/deploy-admin-from-artifact.sh`.
- Health-Check: `https://admin.staging.rebreak.org/`.
---
## 7. Sicherheit
### Runner-Isolation
- Der Runner wird als **Repository-Level Runner** im `rebreak-monorepo` registriert, damit nur dieses Repo ihn nutzen kann.
- Der Runner bekommt ein dediziertes Label: `raynis-builder`.
- Der Workflow fordert das Label explizit an: `runs-on: [self-hosted, raynis-builder]`.
- Der Runner reagiert **nicht** auf Pull-Request-Events — nur auf `push` zu `main` und `workflow_dispatch`.
### SSH-Zugriff
- Ein neuer SSH-Deploy-Key wird auf `api.trucko.org` erzeugt.
- Der Public Key wird auf `staging.rebreak.org` in `/root/.ssh/authorized_keys` eingetragen.
- Der Private Key wird als GitHub Secret (z. B. `STAGING_DEPLOY_KEY`) im Environment `staging` hinterlegt.
### Secrets
- Keine Secrets im Runner-Image.
- Alle sensiblen Daten kommen weiterhin aus GitHub Environments oder Infisical (auf `staging.rebreak.org`).
---
## 8. Fehlerbehandlung
### Build-Fehler
- Wenn `pnpm build` fehlschlägt, bricht der Workflow ab.
- Es wird nichts auf `staging.rebreak.org` kopiert.
### Deploy-Fehler
- `deploy-from-artifact.sh` bricht bei fehlgeschlagenen Prisma-Migrationen ab.
- Der alte `.output-staging`-Ordner bleibt durch atomisches `mv` erhalten.
- Health-Check muss bestehen, sonst schlägt der Workflow fehl.
### Parallelität
- Concurrency-Group bleibt erhalten:
```yaml
concurrency:
group: deploy-staging
cancel-in-progress: false
```
- Parallele Deploys queueen sich, statt sich gegenseitig abzubrechen.
---
## 9. Tests in CI
Aktuell laufen keine automatisierten Tests in den Deploy-Workflows. Mit dem eigenen Runner entstehen hierfür keine zusätzlichen Kosten.
**Empfohlener optionaler nächster Schritt:**
- Vitest-Unit-Tests vor dem Build-Schritt ausführen.
- Reihenfolge: `install → lint → test → build → deploy`.
Dies ist **nicht Teil dieses Designs** und wird in einem separaten Plan behandelt.
---
## 10. Migrationsschritte
1. **Runner auf `api.trucko.org` installieren**
- Node.js 24.11.1, pnpm 10.23.0, git einrichten.
- GitHub Actions Runner herunterladen und konfigurieren.
- Als Service registrieren (`./svc.sh install && ./svc.sh start`).
- Label `raynis-builder` zuweisen.
2. **SSH-Verbindung einrichten**
- Auf `api.trucko.org`: `ssh-keygen -t ed25519 -f ~/.ssh/rebreak-deploy`.
- Public Key auf `staging.rebreak.org` in `/root/.ssh/authorized_keys` eintragen.
- Private Key als GitHub Secret `STAGING_DEPLOY_KEY` im Environment `staging` hinterlegen.
3. **Workflows anpassen**
- `runs-on: ubuntu-latest` → `runs-on: [self-hosted, raynis-builder]`.
- SSH-Setup-Step an neues Secret `STAGING_DEPLOY_KEY` anpassen.
- Node-Setup beibehalten (Version 24.11.1).
4. **Test-Deploy durchführen**
- `workflow_dispatch` auf `main` auslösen.
- Logs auf `api.trucko.org` und `staging.rebreak.org` prüfen.
- Health-Check bestätigen.
5. **Alte Pfade abschalten**
- Nach erfolgreichen Test-Deploys können die alten Webhook-basierten Deploys deaktiviert werden.
- `pm2 stop rebreak-webhook && pm2 save` auf `staging.rebreak.org` (nur auf User-Approval).
---
## 11. Risiken & Mitigationen
| Risiko | Wahrscheinlichkeit | Auswirkung | Mitigation |
|---|---|---|---|
| Runner-Prozess stürzt ab | Niedrig | Hoch | Runner als systemd-Service laufen lassen; GitHub zeigt Runner offline an. |
| Build auf `api.trucko.org` zu langsam | Mittel | Mittel | 8 GB RAM + 8 GB Swap einrichten; SSD statt HDD prüfen. |
| SSH-Verbindung zwischen Servern failt | Niedrig | Hoch | SSH-Key testen; `ssh-keyscan` im Workflow nutzen. |
| Runner wird versehentlich für PRs genutzt | Niedrig | Hoch | Trigger auf `push: branches: [main]` beschränken; kein `pull_request`. |
| Windows-/Native-Builds bleiben kostenpflichtig | Sicher | Niedrig | In separatem Schritt evaluieren (nicht Teil dieses Designs). |
---
## 12. Offene Punkte
1. Exakte Spezifikation von `api.trucko.org` bestätigen (CPU, SSD, OS).
2. Soll der Runner unter einem dedizierten User laufen oder als `root`?
3. Sollen bestehende Webhook-Deploys sofort abgeschaltet oder parallel als Fallback laufen?
4. Sollen Vitest-Tests vor dem Build integriert werden (separater Plan)?
---
## 13. Erwartetes Ergebnis
Nach der Umstellung:
- Backend- und Admin-Builds laufen auf `api.trucko.org`.
- GitHub-Actions-Minutenkosten für diese Workflows fallen nahezu auf null.
- Die Deploy-Mechanik auf `staging.rebreak.org` bleibt unverändert.
- Windows-/Native-Builds bleiben bei GitHub Actions oder werden separat betrachtet.