Files
tessera-ctl/docs/ci-cd-setup.md
T
schalli ea6aa995b2
Tessera CI/CD / Lint & Type Check (push) Successful in 48s
Tessera CI/CD / Tests (push) Successful in 52s
Tessera CI/CD / Build & Publish Images (push) Successful in 3m34s
docs(quick-260914-ku1): Betriebshandbuch — Zwei Kanäle Live und Beta, Freigabe, Hotfix ohne Datenbankänderung, neuer Live-Server; ci-cd-setup auf gemessenen Stand
- anleitung-betrieb.md: neues Kapitel 9 (Kanal, IMAGE_TAG je Server, Freigabe,
  Hotfix-Ablauf mit Regel "Keine Datenbankaenderung als Hotfix", drei Kontrollwege,
  Einrichtung des Live-Servers, Erstfreigabe v1.0.0); Inhaltsverzeichnis, Tabelle in
  Kapitel 1, IMAGE_TAG in Kapitel 3, Etiketten in Kapitel 4, Startzeile in Kapitel 7
- ci-cd-setup.md: REGISTRY_TOKEN und Push ueber localhost:3002, Trigger main/live/v*,
  Jobs quality -> test -> publish, Etiketten- und Build-Arg-Tabellen, D-13 ueberholt,
  Tag-/Branch-Schutz-Empfehlung (T-KU1-04), Fehlerbehebung fuer den Stempel

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
2026-09-14 15:44:16 +02:00

8.3 KiB

Tessera CI/CD Setup

Runbook fuer die Einrichtung der Gitea-basierten CI/CD-Pipeline.

Voraussetzungen

  • Docker und Docker Compose installiert
  • Gitea-Instanz mit aktivierten Actions
  • Zugriff auf die Gitea-Administrationsoberflaeche

1. Gitea-Repository einrichten

  1. In Gitea ein neues Repository erstellen (z.B. tessera-ctl)
  2. Das Repository als Git-Remote hinzufuegen:
git remote add origin https://<gitea-url>/<user>/tessera-ctl.git
  1. In den Repository-Einstellungen unter Settings > Actions sicherstellen, dass Actions aktiviert ist.

2. act_runner registrieren

Der act_runner fuehrt Gitea Actions Workflow-Jobs in Docker-Containern aus.

Runner-Token generieren

  1. In Gitea navigieren zu: Repository > Settings > Actions > Runners (oder Admin-Panel > Actions > Runners fuer globale Runner)
  2. Create registration token klicken
  3. Token kopieren

Runner starten

Die Umgebungsvariablen setzen (z.B. in .env im Projektverzeichnis oder direkt in der Shell):

export GITEA_INSTANCE_URL=https://git.vicolab.de
export GITEA_RUNNER_REGISTRATION_TOKEN=<token-aus-schritt-oben>

Runner starten:

docker compose -f docker-compose.ci.yml up -d

Runner-Status pruefen:

docker compose -f docker-compose.ci.yml logs act_runner

Der Runner registriert sich automatisch bei Gitea und ist bereit, Jobs auszufuehren.

Bestehender Runner

Wenn bereits ein act_runner als separater Docker-Container laeuft (z.B. gitea-runner), kann docker-compose.ci.yml als Dokumentation und Vorlage fuer eine Neueinrichtung verwendet werden. Der bestehende Runner muss nicht ersetzt werden.

Bestehenden Runner pruefen:

docker ps --filter name=gitea-runner

3. Erforderliche Konfiguration

Umgebungsvariablen

Variable Beschreibung Wo setzen
GITEA_INSTANCE_URL URL der Gitea-Instanz .env oder Systemumgebung
GITEA_RUNNER_REGISTRATION_TOKEN Runner-Registrierungstoken .env oder Systemumgebung

Gitea Secrets (fuer die CI-Pipeline)

In Gitea unter Repository > Settings > Actions > Secrets werden die Secrets fuer die Pipeline konfiguriert. Benoetigt wird genau eines:

Secret Beschreibung
REGISTRY_TOKEN Gitea-Zugangstoken (Access Token) mit Schreibrecht auf Pakete (package: write). Wird im Job publish fuer docker login localhost:3002 --password-stdin verwendet.

Das Token erscheint nie im Log: es wird per --password-stdin uebergeben und Gitea maskiert Secret-Werte in der Job-Ausgabe. Das Veroeffentlichungs-Skript .gitea/scripts/publish-images.sh kennt das Token nicht; der Login bleibt im Workflow.

Der Push geht ueber localhost:3002 (Gitea laeuft auf demselben Rechner wie der Runner), weil der Nginx Proxy Manager vor git.vicolab.de grosse Image-Blobs blockt. Das Pullen auf den Servern laeuft ueber git.vicolab.de (docker-compose.prod.yml).

Weitere Secrets bei Bedarf:

  1. In Gitea Settings > Actions > Secrets den Secret anlegen
  2. In .gitea/workflows/ci.yml ueber ${{ secrets.SECRET_NAME }} referenzieren

Wichtig: Secrets niemals in Logs ausgeben oder in Workflow-Dateien hardcoden.

4. Pipeline-Ueberblick

Die CI/CD-Pipeline (.gitea/workflows/ci.yml) laeuft bei jedem Push auf die Zweige main und live sowie bei jedem Tag v* (z. B. v1.0.0) und besteht aus drei aufeinander aufbauenden Jobs:

  1. quality -- Lint und TypeScript Type-Check (Lint ist derzeit ein Leerlauf, siehe WINDOWS #35; der Type-Check ist echt)
  2. test -- Vitest Unit- und Integrationstests
  3. publish -- Docker Images mit Versionsstempel bauen und in die Gitea-Registry veroeffentlichen

Ablauf: quality -> test -> publish (jeder Job nur bei Erfolg des vorherigen). Der Job publish besteht aus drei Schritten: actions/checkout@v4 mit fetch-depth: 0 (volle Historie samt Tags, sonst liefert git describe nichts), Login in die Registry (siehe Abschnitt 3) und der Aufruf von .gitea/scripts/publish-images.sh.

Zwei Kanaele: Etiketten je Anlass

Das Skript .gitea/scripts/publish-images.sh entscheidet allein anhand GITHUB_REF, ob und unter welchen Etiketten veroeffentlicht wird:

Anlass Kanal (APP_CHANNEL) Etiketten in der Registry
Push auf main beta beta und latest (latest ist nur ein Alias fuer beta und entfaellt spaeter)
Tag vX.Y.Z live live und vX.Y.Z
Push auf live ohne Tag -- keine; der Lauf prueft nur (quality, test), das Skript endet mit "nichts zu tun"

Das Kanalmodell fuer den Betrieb (welcher Server welches Etikett zieht, Freigabe, Hotfix) steht in docs/anleitung-betrieb.md, Kapitel 9.

Versionsstempel

Das Skript berechnet vier Werte und gibt sie als --build-arg an beide Dockerfiles (apps/web/Dockerfile, apps/api/Dockerfile):

Build-Arg Quelle
APP_VERSION git describe --tags --always (ohne Tag: kurzer Commit-SHA)
APP_CHANNEL beta oder live, siehe Tabelle oben
APP_COMMIT git rev-parse --short HEAD
APP_BUILD_TIME date -u, ISO-Format

Die API liest die Werte zur Laufzeit (GET /health/version, Startzeile im Log). Das Web-Image bettet NEXT_PUBLIC_APP_* beim Build in das Browser-Bundle ein -- deshalb laeuft die builder-Stufe des Web-Images jetzt bei jedem Pipeline-Lauf neu, die Laufzeit liegt eher bei 4-6 statt 2 Minuten.

Lokale Probe ohne Docker-Aufruf:

GITHUB_REF=refs/tags/v1.2.3 sh .gitea/scripts/publish-images.sh --print-plan

Hinweis: Die fruehere Entscheidung D-13 (Images lokal bauen, keine Registry) ist ueberholt -- seit der Einfuehrung der Gitea-Registry werden Images gepusht und von den Servern per docker compose pull geholt.

5. Sicherheitshinweise

Docker Socket

Der act_runner mountet den Host-Docker-Socket (/var/run/docker.sock), um Jobs in Docker-Containern ausfuehren zu koennen. Das bedeutet:

  • Der Runner hat Zugriff auf den Docker-Daemon des Hosts
  • Er kann Container starten, stoppen und inspizieren

Risikobewertung: Akzeptabel fuer interne CI, da:

  • Nur Claude pusht manuell bei Meilensteinen (D-11)
  • Kein externer Code wird ausgefuehrt
  • Ephemeral Mode ist aktiviert (siehe unten)

Ephemeral Runner

GITEA_RUNNER_EPHEMERAL=1 sorgt dafuer, dass der Runner seine Credentials nach jedem Job widerruft und sich neu registriert. Das verhindert:

  • Persistente Zugriffstokens im Runner-Container
  • Kompromittierung ueber alte Job-Artefakte
  • Seitliche Bewegung zwischen Jobs

Workflow-Dateien

Workflow-Dateien in .gitea/workflows/ werden direkt aus dem Repository geladen. Da nur vertrauenswuerdiger Code gepusht wird (D-11, Claude als einziger Committer), ist das Risiko einer manipulierten Pipeline minimal.

Ein Tag-Push v* ist der Freigabe-Hebel fuer Live: wer ihn setzen darf, kann das live-Etikett neu belegen. Heute hat nur das Konto schalli Schreibrecht (0 Kollaborateure, keine Branch-Regeln). Kommen weitere Konten dazu, in Gitea unter Repository > Settings > Branches / Tags eine Tag-Schutzregel fuer v* und einen Branch-Schutz fuer live anlegen (T-KU1-04).

6. Fehlerbehebung

Runner registriert sich nicht

  1. Pruefen ob GITEA_INSTANCE_URL korrekt und erreichbar ist
  2. Token ggf. neu generieren (Token sind einmalig verwendbar bei Ephemeral Mode)
  3. Runner-Logs pruefen: docker compose -f docker-compose.ci.yml logs act_runner

Pipeline startet nicht

  1. In Gitea pruefen ob Actions fuer das Repository aktiviert ist
  2. Pruefen ob der Runner als "online" angezeigt wird (Gitea > Actions > Runners)
  3. Sicherstellen dass die Workflow-Datei unter .gitea/workflows/ liegt
  4. YAML-Syntax validieren

Docker-Build schlaegt fehl

  1. Sicherstellen dass docker-compose.yml im Arbeitsverzeichnis des Runners erreichbar ist
  2. Docker Daemon Status pruefen: docker info
  3. Disk Space pruefen: df -h

Stempel zeigt dev oder nur eine Kurzkennung statt des Tags

  1. Im Job publish pruefen, dass actions/checkout@v4 mit fetch-depth: 0 auscheckt -- ohne Tags liefert git describe --tags --always nur den SHA
  2. Pruefen, ob der Tag wirklich gepusht wurde: git ls-remote --tags origin
  3. dev bedeutet: das Image wurde ohne Build-Args gebaut (lokal statt ueber das Skript) -- das ist fuer lokale Builds normal