# 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 resources: requests: cpu: 100m memory: 256Mi limits: memory: 512Mi volumes: # Platzhalter — die Betreiberin ergaenzt hier ihre eigene # Volume-Quelle fuer den Namen "uploads" (z.B. ein PVC, das gegen # ein SMB-/NFS-Backend oder einen hostPath gebunden ist), etwa: # - name: uploads # persistentVolumeClaim: # claimName: wabenhain-uploads-pvc - name: uploads # CHANGE-ME: obige emptyDir-Zeile durch die echte Volume-Quelle # ersetzen. emptyDir ist NICHT persistent (Inhalt geht bei jedem # Pod-Neustart verloren) und dient hier nur als Platzhalter, damit # dieses Manifest ohne weitere Aenderung "kubectl apply"-faehig # bleibt. emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: wabenhain-app namespace: wabenhain spec: selector: app: wabenhain-app ports: - port: 80 targetPort: 3000