# Prod-Deploy via vorgebaute Images (Plan B) — Runbook > **Warum:** Der direkte Build auf dem Prod-Coolify läuft in den Deployment-Timeout > (~1 h; Ursache ist Coolifys Build-Pfad — u. a. die ~265-ARG-Injektion, die den > Layer-Cache bei jedem Deploy bricht → Kaltbau). Lösung: Images **einmal auf einem > leistungsfähigen Host bauen**, in die Registry pushen, und der Prod-Host **zieht nur**. > Ergebnis: Prod-Deploy = Pull + Migrate = Minuten statt Stunde. ## Topologie (Stand 2026-09-10) | Rolle | Host | |---|---| | **Build-Host** (baut + pusht) | `192.168.1.155` — lokales Coolify (= local-gitea-Host), amd64, Docker | | **Registry** | **git.certvia.de** (Gitea Container Registry), Namespace `msolarczek` | | **Prod** (`certvia_prod`, GEFIM live) | **coolify.certvia.de** (eigener Server, ≠ 192.168) | | Quelle | git.certvia.de/msolarczek/certvia, Branch `main` | Beteiligte Dateien im Repo: - `docker-compose.coolify.prebuilt.yml` — wie `docker-compose.coolify.yml`, aber die App-Services ziehen `${REGISTRY:-git.certvia.de/msolarczek}/certvia-*:${IMAGE_TAG:-main}` statt zu bauen (`postgres`/`redis` unverändert). - `scripts/build-and-push-images.sh` — baut + pusht die drei Images. Service → Image (Dockerfile-Target): - `app` → **certvia-app** (`runner`) - `migrate`, `worker`, `backup-worker`, `incident-inbound-worker`, `garage-provision` → **certvia-migrate** (`migrate`) - `garage` → **certvia-garage** (`garage`) ## Voraussetzung: Gitea-Token Token in git.certvia.de → Settings → Applications mit Scopes: `read:repository` (Klonen) + `read:package` + `write:package` (Image Push/Pull). ## Ablauf je Release ### 1. Auf dem Build-Host (192.168.1.155) ```bash docker login git.certvia.de -u msolarczek # Passwort = Token git clone https://msolarczek:@git.certvia.de/msolarczek/certvia.git cv-build # oder: cd cv-build && git fetch && git pull cd cv-build && git checkout main && git pull ALSO_MAIN=true ./scripts/build-and-push-images.sh # baut+pusht Tag UND :main ``` > **Wichtig:** `ALSO_MAIN=true` setzen → es wird zusätzlich das bewegliche Tag `:main` > gepusht. Coolify zieht per Default `:main` (siehe Gotcha IMAGE_TAG unten). ### 2. Prod-Host (coolify.certvia.de) einmalig am Registry anmelden ```bash docker login git.certvia.de -u msolarczek # Passwort = Token ``` (oder in der Coolify-UI unter Settings → Docker Registries hinterlegen). Nur beim ersten Mal / nach Token-Wechsel nötig. ### 3. Coolify (certvia_prod, coolify.certvia.de) - **Configuration → „Docker Compose Location"** = `docker-compose.coolify.prebuilt.yml` (einmalig). - Env unverändert: `RUN_DEMO_SEED=false`, `BOOTSTRAP_ADMIN=false`. - **Redeploy.** Log zeigt Pull der `certvia-*:main` → `migrate` (achte auf neue Migration) → `garage`/`garage-provision` → `app` healthy. ### 4. Nach dem Deploy — Bestandsmandanten-Migrationen der Fachdaten Nur nötig, wenn eine Änderung Bestandsmandanten betrifft (z. B. der 5×5-Backfill). In Coolify → certvia_prod → Service `backup-worker`/`worker` → Terminal (oder per SSH `docker exec`): ```bash npx tsx scripts/backfill-risk-5x5.ts # idempotent, alle Mandanten ``` ### 5. Smoke-Test Login → betroffene Modulseiten prüfen (z. B. `/processes`, `/dependencies`). ## Gotchas (aus dem ersten Live-Lauf gelernt) - **`IMAGE_TAG` wird von Coolify NICHT in die Compose-Interpolation gereicht** → die Datei fällt auf `:main` zurück. Deshalb `:main` immer mitpushen (`ALSO_MAIN=true`). SHA-genaues Pinning müsste erst geklärt werden (dann `IMAGE_TAG=` in Coolify-Env). - **Coolify entfernt die alten Container VOR dem Pull.** Fehlt der Ziel-Tag in der Registry, schlägt der Pull fehl und **prod ist unten**. Also *immer erst* Images (inkl. `:main`) pushen, *dann* Redeploy. - **Klon-403:** Ein reiner Package-Token darf nicht klonen — `read:repository` fehlt. - **Migration-Drift ungefährlich:** `prisma migrate deploy` läuft auch dann sauber (Exit 0), wenn die DB eine angewandte Migration hat, die lokal nicht mehr existiert (empirisch geprüft). - Nach Nutzung Token, der im Klartext (URL/History) auftauchte, **widerrufen**. ## Rollback Alten Stand deployen: früheres Image-Tag als `:main` retaggen+pushen (auf dem Build-Host) und Redeploy — oder Compose-Location zurück auf `docker-compose.coolify.yml` (Host-Build, langsam) als Notnagel.