- 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
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
- In Gitea ein neues Repository erstellen (z.B.
tessera-ctl) - Das Repository als Git-Remote hinzufuegen:
git remote add origin https://<gitea-url>/<user>/tessera-ctl.git
- 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
- In Gitea navigieren zu: Repository > Settings > Actions > Runners (oder Admin-Panel > Actions > Runners fuer globale Runner)
- Create registration token klicken
- 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:
- In Gitea Settings > Actions > Secrets den Secret anlegen
- In
.gitea/workflows/ci.ymlueber${{ 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:
- quality -- Lint und TypeScript Type-Check (Lint ist derzeit ein Leerlauf, siehe WINDOWS #35; der Type-Check ist echt)
- test -- Vitest Unit- und Integrationstests
- 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
- Pruefen ob
GITEA_INSTANCE_URLkorrekt und erreichbar ist - Token ggf. neu generieren (Token sind einmalig verwendbar bei Ephemeral Mode)
- Runner-Logs pruefen:
docker compose -f docker-compose.ci.yml logs act_runner
Pipeline startet nicht
- In Gitea pruefen ob Actions fuer das Repository aktiviert ist
- Pruefen ob der Runner als "online" angezeigt wird (Gitea > Actions > Runners)
- Sicherstellen dass die Workflow-Datei unter
.gitea/workflows/liegt - YAML-Syntax validieren
Docker-Build schlaegt fehl
- Sicherstellen dass
docker-compose.ymlim Arbeitsverzeichnis des Runners erreichbar ist - Docker Daemon Status pruefen:
docker info - Disk Space pruefen:
df -h
Stempel zeigt dev oder nur eine Kurzkennung statt des Tags
- Im Job
publishpruefen, dassactions/checkout@v4mitfetch-depth: 0auscheckt -- ohne Tags liefertgit describe --tags --alwaysnur den SHA - Pruefen, ob der Tag wirklich gepusht wurde:
git ls-remote --tags origin devbedeutet: das Image wurde ohne Build-Args gebaut (lokal statt ueber das Skript) -- das ist fuer lokale Builds normal