Dockerfile (Multi-Stage, "output: standalone"), docker-compose.yml mit Caddy als einzigem nach aussen offenem Reverse-Proxy (verhindert X-Forwarded-For-Faelschung fuer das App-eigene Rate-Limiting), Gitea Actions Workflow der bei jedem Push zwei Image-Tags in die Gitea- Container-Registry baut (schlankes Laufzeit-Image + ein Migrations- Image mit Prisma-CLI), sowie rohe Kubernetes-Manifeste (Namespace, ConfigMap, Secret-Vorlage, Postgres-/MySQL-StatefulSet, Migrations-Job, App-Deployment, Ingress) fuer den Cluster-Betrieb. Siehe k8s/README.md fuer den vollstaendigen Einrichtungs-/Deployment-Ablauf.
4.3 KiB
Wabenhain in Kubernetes
Rohe Manifeste, mit kubectl apply -f k8s/<datei> einzeln oder als Ordner
anwendbar. Nummerierung = empfohlene Reihenfolge.
Einmalige Vorbereitung
-
Gitea Actions:
.gitea/workflows/docker-build.ymlbaut bei jedem Push aufmainzwei Image-Tags in der Gitea-Container-Registry:<registry>/<owner>/wabenhain:latest(+:sha-<kurzhash>,:vX.Y.Zbei Tags) — das schlanke Laufzeit-Image fuer05-app-deployment.yaml.<registry>/<owner>/wabenhain:migrate-<sha>— enthaelt zusaetzlich die Prisma-CLI/tsx, fuer04-migrate-job.yaml.
Voraussetzung: ein Repo-/Org-Secret
REGISTRY_TOKENin Gitea anlegen (Personal Access Token mitpackage-Scope, unter Benutzereinstellungen → Anwendungen → Access Tokens erzeugen, dann unter Repo-Einstellungen → Actions → Secrets alsREGISTRY_TOKENhinterlegen). Der automatisch von Gitea Actions bereitgestellteGITEA_TOKENreicht dafuer aktuell NICHT aus (fehlendes Package-Write-Recht, Stand heute). -
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 generiertscripts/generate-prisma-clients.mjs(Teil vonpnpm build, laeuft also automatisch bei jedem Image-Build) BEIDE Varianten ins selbe Image; die Wahl zwischen ihnen passiert zur Laufzeit ueberDATABASE_PROVIDER, siehesrc/lib/prisma.ts. Ein Image reicht also fuer Postgres UND MySQL — nurDATABASE_PROVIDER/DATABASE_URLin01-configmap.yaml/02-secret.yamlmuessen zur tatsaechlich gewaehlten Datenbank passen. -
k8s/02-secret.example.yamlnachk8s/02-secret.yamlkopieren (per.gitignoreausgeschlossen — NIE mit echten Werten committen) und ausfuellen. Alternativ direkt perkubectl create secret, siehe Kommentar in der Beispieldatei. -
01-configmap.yaml:DATABASE_PROVIDER(postgresql/mysql) undNEXT_PUBLIC_SITE_URL(echte Domain) anpassen. -
In
04-migrate-job.yamlund05-app-deployment.yamldieimage:-Platzhalter (git.example.com/OWNER/wabenhain:...) durch die tatsaechliche Registry/Owner/Tag aus Schritt 1 ersetzen. In06-ingress.yamlshop.example.comdurch die echte Domain ersetzen (zweimal:host:undtls.hosts).
Deployment
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
# Migrationen + Seed (Admin-Konto, Beispieldaten) — vor jedem neuen
# Image-Tag erneut ausfuehren:
kubectl delete job wabenhain-migrate -n wabenhain --ignore-not-found
kubectl apply -f k8s/04-migrate-job.yaml
kubectl wait --for=condition=complete job/wabenhain-migrate -n wabenhain --timeout=120s
kubectl apply -f k8s/05-app-deployment.yaml
kubectl apply -f k8s/06-ingress.yaml
Bei einem neuen Image (Redeploy)
kubectl delete job wabenhain-migrate -n wabenhain --ignore-not-found
kubectl apply -f k8s/04-migrate-job.yaml
kubectl wait --for=condition=complete job/wabenhain-migrate -n wabenhain --timeout=120s
kubectl rollout restart deployment/wabenhain-app -n wabenhain
Bekannte Grenzen dieser Manifeste
replicas: 1in05-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 zuerstlib/rate-limit.tsauf Redis o.ae. umstellen.- Kein
HorizontalPodAutoscaler, keinPodDisruptionBudget, keineNetworkPolicy— 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_URLin02-secret.yamleinfach auf den externen Endpunkt zeigen lassen,03-postgres.yaml/03-mysql.yamldann nicht anwenden.