feat: SMB-PersistentVolumes fuer Medien und Datenbank-Sicherungen

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) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-09-27 20:11:04 +02:00
1 parent 95e3733ab8
commit 24939b58d5
4 files changed
+120 -5

No files matched your search

+1 -5
View File
@@ -108,10 +108,6 @@ Die Software trifft keine Storno-Entscheidung, sie setzt sie nur nachvollziehbar
## 9. Medien ## 9. Medien
Dateien (jpg, png, webp, avif, mp4, webm) in das Volume `artista-modelcamp-media` kopieren: 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/<dateiname>`. Im Pod ist das Volume schreibgeschützt eingehängt.
```bash
kubectl -n artista cp villa-aussen.jpg <app-pod>:/app/media/villa-aussen.jpg # Volume ist im App-Pod read-only → einen Hilfs-Pod mit Schreibzugriff nutzen
```
Danach in `src/content/site.ts` eintragen. Hotlinking fremder Bilder, etwa von Booking.com, ist nicht vorgesehen: Nur Bilder mit geklärter Nutzungsberechtigung ablegen. Danach in `src/content/site.ts` eintragen. Hotlinking fremder Bilder, etwa von Booking.com, ist nicht vorgesehen: Nur Bilder mit geklärter Nutzungsberechtigung ablegen.
@@ -7,6 +7,9 @@ namespace: artista
resources: resources:
- ../../base - ../../base
- ingress.yaml - 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: images:
# Gebaut von .gitea/workflows/docker-build.yml: Git-Tag "v0.1.0" pushen # Gebaut von .gitea/workflows/docker-build.yml: Git-Tag "v0.1.0" pushen
@@ -20,6 +23,26 @@ images:
newTag: "0.1.0" newTag: "0.1.0"
patches: 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 } - target: { kind: ConfigMap, name: artista-modelcamp-config }
patch: |- patch: |-
- op: replace - op: replace
+79
View File
@@ -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" (//<nas>/<freigabe>/<ordner>) 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
+17
View File
@@ -26,3 +26,20 @@ stringData:
SMTP_HOST: "<smtp.example.org>" SMTP_HOST: "<smtp.example.org>"
SMTP_USER: "<benutzer>" SMTP_USER: "<benutzer>"
SMTP_PASSWORD: "<passwort>" SMTP_PASSWORD: "<passwort>"
---
# 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: "<nas-benutzer>"
password: "<nas-passwort>"
# Optional bei Domaenenkonten:
# domain: "<domaene>"