# image: unten mit der tatsaechlichen Registry/Tag aus der Gitea-Actions- # Pipeline ersetzen. Kein separater Migrations-Job mehr noetig: der # Container fuehrt "prisma migrate deploy" + "prisma db seed" selbst aus, # BEVOR er den Server startet (siehe Dockerfile-CMD in der runner-Stage) — # beide Schritte sind idempotent, laufen also bei jedem Neustart gefahrlos # erneut. Readiness-/Liveness-Probes greifen automatisch erst, sobald Port # 3000 offen ist, also nach abgeschlossener Migration/Seed. apiVersion: apps/v1 kind: Deployment metadata: name: wabenhain-app namespace: wabenhain spec: # ACHTUNG bevor du hochskalierst: lib/rate-limit.ts haelt Login-/2FA-/ # Checkout-Limits aktuell im Prozessspeicher, nicht in einem gemeinsamen # Store. Mit replicas > 1 verteilt sich derselbe Nutzer per Load-Balancing # auf mehrere Prozesse mit je eigenem Zaehler — das Limit wird effektiv um # den Skalierungsfaktor schwaecher (2 Replicas = 2x mehr Versuche moeglich), # ohne dass das im Frontend sichtbar waere. Fuer replicas > 1 zuerst # lib/rate-limit.ts auf einen gemeinsamen Store (z.B. Redis) umstellen. replicas: 1 selector: matchLabels: app: wabenhain-app template: metadata: labels: app: wabenhain-app spec: # fsGroup=1001 muss zur "nodejs"-Gruppe (gid 1001) passen, die das # Dockerfile fuer den non-root "nextjs"-Laufzeitbenutzer anlegt: ohne # dieses Feld mountet Kubernetes das "uploads"-Volume (egal ob emptyDir # oder ein echtes PVC) mit root:root-Besitz — das ueberschreibt den im # Image bereits per chown gesetzten Besitzer von /app/uploads # vollstaendig, und der nicht-root laufende Container koennte trotzdem # keine Datei dort anlegen (EACCES bei jedem Admin-Upload). fsGroup # sorgt dafuer, dass Kubernetes JEDES gemountete Volume zusaetzlich der # Gruppe 1001 zuordnet und gruppen-schreibbar macht. securityContext: fsGroup: 1001 containers: - name: app image: git.encry.de/nick.rosenloecher/wabenhain:latest ports: - containerPort: 3000 envFrom: - configMapRef: name: wabenhain-config - secretRef: name: wabenhain-secrets volumeMounts: # Muss auf denselben Pfad zeigen wie UPLOAD_DIR in # 01-configmap.yaml. Das "uploads"-Volume selbst wird HIER # bewusst nicht definiert (kein PV/PVC in diesem Manifest) — das # haengt vom tatsaechlichen Storage-Backend ab (SMB/NFS/ # hostPath/...), das die Betreiberin bereitstellt. Unten im # "volumes:"-Block einen passenden Eintrag mit demselben Namen # ("uploads") ergaenzen, z.B. ueber eine # persistentVolumeClaim.claimName, sonst startet der Pod nicht # (fehlende Volume-Referenz). - name: uploads mountPath: /app/uploads readinessProbe: httpGet: path: / port: 3000 initialDelaySeconds: 10 periodSeconds: 10 livenessProbe: httpGet: path: / port: 3000 # initialDelaySeconds/failureThreshold grosszuegiger als sonst # ueblich: der Container migriert/seedet die DB selbst vor dem # Serverstart (siehe Kommentar oben) — genug Spielraum, damit ein # laengerer erster Migrationslauf nicht faelschlich als haengender # Prozess gewertet und der Container neu gestartet wird. initialDelaySeconds: 30 periodSeconds: 30 failureThreshold: 5 # Bemessen nach dem teuersten Vorgang der Anwendung, dem # Admin-Video-Upload: Node laedt den multipart-Body beim # request.formData() vollstaendig in den Speicher, und die Datei # darf bis zu 100 MB gross sein (MAX_UPLOAD_VIDEO_BYTES in # lib/uploads.ts). Zusammen mit dem Grundverbrauch des # Next.js-Servers sprengte das ein Limit von 512Mi — der Kernel # beendet den Prozess dann mitten im Upload (OOMKilled), und im # Browser kommt davon nur die HTML-Fehlerseite des Reverse-Proxy an # ("Unexpected token '<', "