diff --git a/k8s/05-app-deployment.yaml b/k8s/05-app-deployment.yaml index 29ee5a5..88573d9 100644 --- a/k8s/05-app-deployment.yaml +++ b/k8s/05-app-deployment.yaml @@ -51,8 +51,25 @@ spec: # 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 + # sorgt dafuer, dass Kubernetes das gemountete Volume zusaetzlich der # 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: fsGroup: 1001 containers: diff --git a/k8s/README.md b/k8s/README.md index be226ab..f7fab7a 100644 --- a/k8s/README.md +++ b/k8s/README.md @@ -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 „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 `07-backup-cronjob.yaml` legt jede Nacht um 03:15 Uhr eine