From 24939b58d587e307bd7519f8aa223650bef714a9 Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Sun, 27 Sep 2026 20:11:04 +0200 Subject: [PATCH] feat: SMB-PersistentVolumes fuer Medien und Datenbank-Sicherungen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Statische PVs ueber csi-driver-smb (smb.csi.k8s.io), fest an die PVCs artista-modelcamp-media (App liest, uid 1001) und artista-modelcamp-db-backup (pg_dump-Job, uid 70, 0700/0600) gebunden, reclaimPolicy Retain. Zugang ueber Secret artista-modelcamp-smb. Das PostgreSQL-Datenverzeichnis bleibt bewusst auf Blockspeicher (SMB erfuellt dessen Sperr- und fsync-Anforderungen nicht, Briefing §13); die Datenbank landet ueber die taeglichen Dumps trotzdem auf dem NAS. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/BETRIEB.md | 6 +- k8s/overlays/production/kustomization.yaml | 23 +++++++ k8s/overlays/production/smb-volumes.yaml | 79 ++++++++++++++++++++++ k8s/secret.example.yaml | 17 +++++ 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 k8s/overlays/production/smb-volumes.yaml diff --git a/docs/BETRIEB.md b/docs/BETRIEB.md index 577d9c5..42be448 100644 --- a/docs/BETRIEB.md +++ b/docs/BETRIEB.md @@ -108,10 +108,6 @@ Die Software trifft keine Storno-Entscheidung, sie setzt sie nur nachvollziehbar ## 9. Medien -Dateien (jpg, png, webp, avif, mp4, webm) in das Volume `artista-modelcamp-media` kopieren: - -```bash -kubectl -n artista cp villa-aussen.jpg :/app/media/villa-aussen.jpg # Volume ist im App-Pod read-only → einen Hilfs-Pod mit Schreibzugriff nutzen -``` +Dateien (jpg, png, webp, avif, mp4, webm) direkt in den SMB-Ordner `modelcamp-media` legen, z. B. über den Windows-Explorer (`\\nas…\artista\modelcamp-media`). Die App sieht sie sofort unter `/media/`. Im Pod ist das Volume schreibgeschützt eingehängt. Danach in `src/content/site.ts` eintragen. Hotlinking fremder Bilder, etwa von Booking.com, ist nicht vorgesehen: Nur Bilder mit geklärter Nutzungsberechtigung ablegen. diff --git a/k8s/overlays/production/kustomization.yaml b/k8s/overlays/production/kustomization.yaml index 8249efd..e1297ff 100644 --- a/k8s/overlays/production/kustomization.yaml +++ b/k8s/overlays/production/kustomization.yaml @@ -7,6 +7,9 @@ namespace: artista resources: - ../../base - ingress.yaml + # Medien und Sicherungen auf SMB (PostgreSQL bewusst nicht, siehe Datei). + # Ohne SMB: diese Zeile und die beiden PVC-Patches unten entfernen. + - smb-volumes.yaml images: # Gebaut von .gitea/workflows/docker-build.yml: Git-Tag "v0.1.0" pushen @@ -20,6 +23,26 @@ images: newTag: "0.1.0" patches: + # PVCs fest an die SMB-PersistentVolumes binden (statisch, ohne StorageClass). + - target: { kind: PersistentVolumeClaim, name: artista-modelcamp-media } + patch: |- + - op: add + path: /spec/storageClassName + value: "" + - op: add + path: /spec/volumeName + value: artista-modelcamp-media-smb + - target: { kind: PersistentVolumeClaim, name: artista-modelcamp-db-backup } + patch: |- + - op: add + path: /spec/storageClassName + value: "" + - op: add + path: /spec/volumeName + value: artista-modelcamp-db-backup-smb + - op: replace + path: /spec/accessModes + value: ["ReadWriteMany"] - target: { kind: ConfigMap, name: artista-modelcamp-config } patch: |- - op: replace diff --git a/k8s/overlays/production/smb-volumes.yaml b/k8s/overlays/production/smb-volumes.yaml new file mode 100644 index 0000000..452d3a0 --- /dev/null +++ b/k8s/overlays/production/smb-volumes.yaml @@ -0,0 +1,79 @@ +# PersistentVolumes auf einer SMB-Freigabe (csi-driver-smb, smb.csi.k8s.io). +# +# VORAUSSETZUNG: csi-driver-smb im Cluster installiert, z. B.: +# helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts +# helm install csi-driver-smb csi-driver-smb/csi-driver-smb -n kube-system +# und das Zugangs-Secret "artista-modelcamp-smb" (k8s/secret.example.yaml). +# +# ANZUPASSEN: "source" (////) je Volume. Die Ordner +# muessen auf der Freigabe bereits existieren. +# +# BEWUSST NICHT AUF SMB: das PostgreSQL-Datenverzeichnis. SMB bildet +# POSIX-Sperren, fsync-Garantien und Dateirechte nicht so ab, wie PostgreSQL +# sie fuer Absturzsicherheit braucht (Briefing §13). Die Datenbank bleibt auf +# Blockspeicher und wird taeglich per pg_dump auf das Backup-Volume unten +# gesichert — damit liegen die Geschaeftsdaten trotzdem auf dem NAS. +# +# Rechte: fsGroup wirkt auf SMB nicht. Besitz und Rechte setzen deshalb +# uid/gid/dir_mode/file_mode in den mountOptions (Muster aus Wabenhain). +# Aenderungen an mountOptions greifen erst beim naechsten Einhaengen. +# reclaimPolicy Retain: Loeschen von PVC/PV laesst die Dateien auf dem NAS. + +# --- Medien (Bilder/Videos) ---------------------------------------------------- +# Die App liest nur (readOnly-Mount). Neue Bilder legst du direkt ueber die +# SMB-Freigabe ab, z. B. vom Windows-Explorer aus. +apiVersion: v1 +kind: PersistentVolume +metadata: + name: artista-modelcamp-media-smb +spec: + capacity: + storage: 5Gi + accessModes: ["ReadWriteMany"] + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + mountOptions: + - vers=3.0 + - uid=1001 # Containerbenutzer "nextjs" (Dockerfile) + - gid=1001 + - dir_mode=0770 + - file_mode=0660 + - mfsymlinks + - nobrl + csi: + driver: smb.csi.k8s.io + # Muss im Cluster eindeutig sein. + volumeHandle: artista-modelcamp-media-smb + volumeAttributes: + source: //nas.example.lan/artista/modelcamp-media + nodeStageSecretRef: + name: artista-modelcamp-smb + namespace: artista +--- +# --- Datenbank-Sicherungen ------------------------------------------------------ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: artista-modelcamp-db-backup-smb +spec: + capacity: + storage: 10Gi + accessModes: ["ReadWriteMany"] + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + mountOptions: + - vers=3.0 + - uid=70 # Benutzer "postgres" im pg_dump-Job (postgres:18-alpine) + - gid=70 + - dir_mode=0700 # Sicherungen enthalten personenbezogene Daten + - file_mode=0600 + - mfsymlinks + - nobrl + csi: + driver: smb.csi.k8s.io + volumeHandle: artista-modelcamp-db-backup-smb + volumeAttributes: + source: //nas.example.lan/artista/modelcamp-backup + nodeStageSecretRef: + name: artista-modelcamp-smb + namespace: artista diff --git a/k8s/secret.example.yaml b/k8s/secret.example.yaml index 9e24004..94450b9 100644 --- a/k8s/secret.example.yaml +++ b/k8s/secret.example.yaml @@ -26,3 +26,20 @@ stringData: SMTP_HOST: "" SMTP_USER: "" SMTP_PASSWORD: "" +--- +# Zugang zur SMB-Freigabe fuer die PersistentVolumes +# (k8s/overlays/production/smb-volumes.yaml). Eigener, auf die Artista- +# Ordner beschraenkter NAS-Benutzer empfohlen. +# kubectl -n artista create secret generic artista-modelcamp-smb \ +# --from-literal=username='…' --from-literal=password='…' +apiVersion: v1 +kind: Secret +metadata: + name: artista-modelcamp-smb + namespace: artista +type: Opaque +stringData: + username: "" + password: "" + # Optional bei Domaenenkonten: + # domain: ""