# Wabenhain in Kubernetes Rohe Manifeste, mit `kubectl apply -f k8s/` einzeln oder als Ordner anwendbar. Nummerierung = empfohlene Reihenfolge. ## Einmalige Vorbereitung 1. **Gitea Actions**: `.gitea/workflows/docker-build.yml` baut bei jedem Push auf `main` das Image `//wabenhain:latest` (+ `:sha-`, `:vX.Y.Z` bei Tags) in der Gitea-Container-Registry. Ein einzelnes Image reicht fuer `05-app-deployment.yaml` — es traegt sowohl die Next.js-App als auch die Prisma-CLI/tsx und migriert/seedet die Datenbank beim Start selbst (siehe Punkt 2 unten), kein separates Migrations-Image mehr. Voraussetzung: ein Repo-/Org-Secret `REGISTRY_TOKEN` in Gitea anlegen (Personal Access Token mit `package`-Scope, unter Benutzereinstellungen → Anwendungen → Access Tokens erzeugen, dann unter Repo-Einstellungen → Actions → Secrets als `REGISTRY_TOKEN` hinterlegen). Der automatisch von Gitea Actions bereitgestellte `GITEA_TOKEN` reicht dafuer aktuell NICHT aus (fehlendes Package-Write-Recht, Stand heute). 2. **Ein Docker-Image ist Provider-uebergreifend**: Prisma generiert den Client Provider-spezifisch — ein `.next/standalone`-Build kann seinen generierten Client nicht zur Laufzeit wechseln. Deshalb generiert `scripts/generate-prisma-clients.mjs` (Teil von `pnpm build`, laeuft also automatisch bei jedem Image-Build) BEIDE Varianten ins selbe Image; die Wahl zwischen ihnen passiert zur Laufzeit ueber `DATABASE_PROVIDER`, siehe `src/lib/prisma.ts`. Ein Image reicht also fuer Postgres UND MySQL — nur `DATABASE_PROVIDER`/`DATABASE_URL` in `01-configmap.yaml`/ `02-secret.yaml` muessen zur tatsaechlich gewaehlten Datenbank passen. Beim Container-Start fuehrt derselbe Prozess erst `prisma migrate deploy` und `prisma db seed` aus, BEVOR der Next.js-Server startet (siehe Dockerfile-CMD in der `runner`-Stage) — beide Schritte sind idempotent und bei jedem Neustart gefahrlos, kein separater Migrations-Job noetig. 3. `k8s/02-secret.example.yaml` nach `k8s/02-secret.yaml` kopieren (per `.gitignore` ausgeschlossen — NIE mit echten Werten committen) und ausfuellen. Alternativ direkt per `kubectl create secret`, siehe Kommentar in der Beispieldatei. 4. `01-configmap.yaml`: `DATABASE_PROVIDER` (postgresql/mysql) und `NEXT_PUBLIC_SITE_URL` (echte Domain) anpassen. 5. `image:` in `05-app-deployment.yaml` zeigt bereits auf `git.encry.de/nick.rosenloecher/wabenhain` — nur noch den Tag pruefen (`:latest` passt fuer den jeweils neuesten `main`-Build). In `06-ingress.yaml` `shop.example.com` durch die echte Domain ersetzen (zweimal: `host:` und `tls.hosts`). ## Deployment ```bash kubectl apply -f k8s/00-namespace.yaml kubectl apply -f k8s/01-configmap.yaml kubectl apply -f k8s/02-secret.yaml # Nur EINE der beiden Datenbanken anwenden, passend zu DATABASE_PROVIDER: kubectl apply -f k8s/03-postgres.yaml # kubectl apply -f k8s/03-mysql.yaml kubectl wait --for=condition=ready pod -l app=wabenhain-postgres -n wabenhain --timeout=120s kubectl apply -f k8s/05-app-deployment.yaml kubectl apply -f k8s/06-ingress.yaml ``` Migrationen + Seed (nur Admin-Konto, KEINE Beispieldaten — siehe Punkt 2 oben) laufen automatisch beim Container-Start — `kubectl rollout status deployment/wabenhain-app -n wabenhain` zeigt, wann der erste Pod bereit ist. ## Bei einem neuen Image (Redeploy) ```bash kubectl rollout restart deployment/wabenhain-app -n wabenhain ``` Migrationen + Seed laufen automatisch erneut beim Start jedes neuen Pods (idempotent, siehe oben). ## Bekannte Grenzen dieser Manifeste - **`replicas: 1`** in `05-app-deployment.yaml`, bewusst nicht mehr: das Login-/2FA-/Checkout-Rate-Limiting (`lib/rate-limit.ts`) haelt seinen Zustand im Prozessspeicher, nicht in einem gemeinsamen Store. Mehrere Replicas wuerden das Limit unbemerkt proportional aufweichen. Fuer horizontale Skalierung zuerst `lib/rate-limit.ts` auf Redis o.ae. umstellen. - Kein `HorizontalPodAutoscaler`, kein `PodDisruptionBudget`, keine `NetworkPolicy` — je nach Cluster/Anforderungen ergaenzen. - Die Postgres-/MySQL-StatefulSets sind Single-Instance ohne Replikation/ Backup-Automation. Fuer produktiven Betrieb einen Managed-Datenbank-Dienst oder einen dedizierten DB-Operator (z.B. CloudNativePG) in Erwaegung ziehen — `DATABASE_URL` in `02-secret.yaml` einfach auf den externen Endpunkt zeigen lassen, `03-postgres.yaml`/`03-mysql.yaml` dann nicht anwenden.