docs: fsGroup wirkt bei SMB/NFS nicht — Rechte gehoeren in die mountOptions
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m8s

Der Kommentar am fsGroup-Feld behauptete, Kubernetes ordne damit JEDES
gemountete Volume der Gruppe 1001 zu. Das stimmt nur fuer blockbasierten
Speicher.

Bei SMB/CIFS und NFS wird fsGroup ignoriert: diese Protokolle kennen keinen
per-Datei-Unix-Besitz, den der Knoten nachtraeglich aendern koennte. Ohne
uid/gid in den mountOptions erscheint dort alles als root:root, und der als
uid 1001 laufende Container scheitert bei jedem Upload mit EACCES — also
genau die Meldung "Die Datei konnte nicht gespeichert werden", ohne dass am
Deployment etwas falsch aussieht.

k8s/README.md bekommt dafuer einen eigenen Abschnitt: Diagnose im laufenden
Pod, die noetigen mountOptions (uid=1001, gid=1001 zusaetzlich zu
dir_mode/file_mode) und der Hinweis, dass Aenderungen daran erst beim
naechsten Einhaengen greifen, ein Rollout-Restart also dazugehoert.

Ebenfalls vermerkt: noperm umgeht die Rechtepruefung, statt den Besitz
richtigzustellen — es ersetzt uid/gid nicht.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5 committed 2026-09-17 06:59:03 +02:00
1 parent 625b73a8c8
commit 425fd76bc1
2 files changed
+85 -1

No files matched your search

+18 -1
View File
@@ -51,8 +51,25 @@ spec:
# Image bereits per chown gesetzten Besitzer von /app/uploads # Image bereits per chown gesetzten Besitzer von /app/uploads
# vollstaendig, und der nicht-root laufende Container koennte trotzdem # vollstaendig, und der nicht-root laufende Container koennte trotzdem
# keine Datei dort anlegen (EACCES bei jedem Admin-Upload). fsGroup # keine Datei dort anlegen (EACCES bei jedem Admin-Upload). fsGroup
# sorgt dafuer, dass Kubernetes JEDES gemountete Volume zusaetzlich der # sorgt dafuer, dass Kubernetes das gemountete Volume zusaetzlich der
# Gruppe 1001 zuordnet und gruppen-schreibbar macht. # Gruppe 1001 zuordnet und gruppen-schreibbar macht.
#
# ACHTUNG, GILT NICHT FUER JEDES BACKEND: fsGroup wirkt nur dort, wo
# Kubernetes den Besitz tatsaechlich setzen kann — also bei
# blockbasiertem Speicher. Bei SMB/CIFS und NFS wird es IGNORIERT, weil
# diese Protokolle keinen per-Datei-Unix-Besitz kennen, den der Knoten
# nachtraeglich aendern koennte. Dort gehoert die Zuordnung in die
# mountOptions des PersistentVolume:
#
# mountOptions:
# - uid=1001
# - gid=1001
# - dir_mode=0770
# - file_mode=0660
#
# Ohne uid/gid erscheint bei SMB ALLES als root:root, und der Container
# scheitert trotz fsGroup mit EACCES. Siehe k8s/README.md, Abschnitt
# "Uploads lassen sich nicht speichern".
securityContext: securityContext:
fsGroup: 1001 fsGroup: 1001
containers: containers:
+67
View File
@@ -221,6 +221,73 @@ Speicher- und CPU-Bedarf nicht mehr von der Größe des Knotens abhängt — sie
erfolgreicher Upload beim nächsten Neustart trotzdem weg. Siehe erfolgreicher Upload beim nächsten Neustart trotzdem weg. Siehe
„Bilder/Videos verschwinden nach jedem Redeploy" oben. „Bilder/Videos verschwinden nach jedem Redeploy" oben.
## Uploads lassen sich nicht speichern
Symptom: Im Admin erscheint „Die Datei konnte nicht gespeichert werden. Bitte
informiere die Technik." Im Pod-Log steht dahinter ein `EACCES`.
Ursache ist fast immer der Besitz des gemounteten Volumes. Der Container läuft
als **`nextjs`, uid 1001, Gruppe `nodejs` gid 1001** (siehe `Dockerfile`). Das
Image setzt zwar `chown nextjs:nodejs /app/uploads`, aber ein darübergelegtes
Volume überschreibt das vollständig.
Zuerst feststellen, was der Container tatsächlich sieht:
```bash
kubectl -n wabenhain exec deploy/wabenhain-app -- sh -c \
'id; ls -ld /app/uploads /app/invoices; \
touch /app/uploads/.probe && echo SCHREIBEN_OK || echo SCHREIBEN_FEHLT'
```
Der Fix hängt am Speicher-Backend — die beiden Wege gelten für verschiedene
Fälle, nicht alternativ:
### Blockspeicher (die meisten CSI-Treiber)
`securityContext.fsGroup: 1001` im Deployment. Kubernetes ordnet das Volume
dann der Gruppe 1001 zu und macht es gruppenschreibbar. Steht bereits in
`05-app-deployment.yaml`.
### SMB/CIFS und NFS
**Hier wird `fsGroup` ignoriert.** Diese Protokolle kennen keinen
per-Datei-Unix-Besitz, den der Knoten nachträglich ändern könnte; ohne
Zuordnung erscheint alles als `root:root`, und der Container scheitert trotz
`fsGroup` mit `EACCES`. Die Zuordnung gehört in die `mountOptions` des
PersistentVolume:
```yaml
spec:
mountOptions:
- vers=3.0
- uid=1001 # muss zum Containerbenutzer passen
- gid=1001
- dir_mode=0770
- file_mode=0660
- mfsymlinks
- nobrl # keine Byte-Range-Locks über SMB
```
`dir_mode`/`file_mode` allein genügen nicht: sie bestimmen nur, welche Rechte
angezeigt werden — wem die Datei gehört, entscheiden `uid`/`gid`.
`noperm` (der Client prüft Rechte gar nicht erst) wirkt in vielen Aufbauten
ebenfalls, ist aber die schwächere Zusicherung: es umgeht die Prüfung, statt
den Besitz richtigzustellen. `uid`/`gid` also auch dann setzen, wenn `noperm`
bereits gesetzt ist.
**Änderungen an `mountOptions` greifen erst beim nächsten Einhängen.** Nach dem
Anpassen des PV den Pod neu starten:
```bash
kubectl -n wabenhain rollout restart deploy/wabenhain-app
```
Lässt sich das PV nicht mehr ändern (bei bereits gebundenen PVs je nach
Kubernetes-Version), PVC und PV löschen und neu anlegen. Bei
`persistentVolumeReclaimPolicy: Retain` bleiben die Daten auf der Freigabe
erhalten.
## Sicherung und Wiederherstellung ## Sicherung und Wiederherstellung
`07-backup-cronjob.yaml` legt jede Nacht um 03:15 Uhr eine `07-backup-cronjob.yaml` legt jede Nacht um 03:15 Uhr eine