feat: fehlende Upload-Dateien werden im Admin sofort gemeldet
Nach einem Redeploy waren alle hochgeladenen Bilder und Videos weg. Die
Ursache war bereits in a78c1cd behoben — das Volume "uploads" im
App-Deployment ist dort vom Platzhalter "emptyDir" auf einen
PersistentVolumeClaim umgestellt. Der Commit liegt auch auf origin/main.
Was fehlte, ist der Schritt danach: die Gitea-Pipeline baut nur das Image
und wendet KEINE Kubernetes-Manifeste an. Ein "kubectl rollout restart"
holt das neue Image, laesst die Deployment-Definition im Cluster aber
unveraendert — dort steht also weiterhin emptyDir. k8s/README.md bekommt
dafuer einen eigenen Abschnitt mit dem genauen Ablauf: erst pruefen, was
im Cluster tatsaechlich als Volume eingetragen ist, dann PVC und
Deployment anwenden, dann gegenpruefen.
Zusaetzlich das eigentliche Problem an diesem Ausfall: er ist unsichtbar.
Die Datenbank behaelt ihre Bildpfade, die Dateien dahinter fehlen, und im
Shop erscheinen einfach leere Flaechen — keine Fehlermeldung, kein
Log-Eintrag. Gemerkt hat man es erst, wenn jemand hingeschaut hat.
lib/upload-health.ts gleicht deshalb ab, ob die in Product/Harvest/Batch
und in den Inhaltsfeldern hinterlegten Pfade als Dateien vorliegen. Das
Admin-Dashboard zeigt bei Abweichung eine Warnung mit Anzahl und
Beispielpfaden samt Hinweis auf die Ursache. Der Abgleich laeuft bewusst
nach den Kennzahlen und mit eigenem catch: schlaegt er fehl, zeigt das
Dashboard trotzdem seine Zahlen. Obergrenze 300 gepruefte Pfade, damit die
Seite nicht an Dateisystemzugriffen haengt.
Bilder und Videos nutzen denselben UPLOAD_DIR (lib/uploads.ts), auch der
Video-Upload ueber den Umweg ueber ein Temp-Verzeichnis — es gibt also
keinen zweiten Speicherort, der getrennt behandelt werden muesste.
Gegen die lokale Datenbank geprueft: ohne Referenzen meldet der Abgleich
0/0, mit einem absichtlich auf eine nicht vorhandene Datei gesetzten
Produktbild 1 von 1 fehlend samt Pfad als Beleg, nach dem Zuruecksetzen
wieder 0/0.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
bdce9b6a0a
commit
c8ddcec04c
6 files changed
+182
No files matched your search
@@ -121,6 +121,50 @@ Redeploy.
|
||||
`02-secret.yaml` einfach auf den externen Endpunkt zeigen lassen,
|
||||
`03-postgres.yaml`/`03-mysql.yaml` dann nicht anwenden.
|
||||
|
||||
## Bilder/Videos verschwinden nach jedem Redeploy
|
||||
|
||||
Symptom: nach einem Redeploy sind alle hochgeladenen Produkt-, Ernten- und
|
||||
Inhaltsbilder weg und muessen neu hochgeladen werden.
|
||||
|
||||
Ursache: das Volume `uploads` im App-Deployment ist noch ein `emptyDir`.
|
||||
Das ist an die Lebensdauer des Pods gebunden — jeder Neustart loescht es.
|
||||
Die Datenbank behaelt dabei ihre Bildpfade, die Dateien dahinter sind aber
|
||||
fort; im Shop erscheinen deshalb leere Flaechen statt einer Fehlermeldung.
|
||||
|
||||
Wichtig: Die Gitea-Pipeline baut nur das Image. Sie wendet **keine**
|
||||
Kubernetes-Manifeste an. Ein `kubectl rollout restart` holt zwar das neue
|
||||
Image, laesst die Deployment-Definition im Cluster aber unveraendert — die
|
||||
Korrektur unten muss deshalb einmal von Hand angewendet werden:
|
||||
|
||||
```bash
|
||||
# 1. Aktuellen Zustand pruefen — steht hier "emptyDir", ist genau das die Ursache:
|
||||
kubectl get deployment wabenhain-app -n wabenhain -o jsonpath='{.spec.template.spec.volumes[?(@.name=="uploads")]}{"
|
||||
"}'
|
||||
|
||||
# 2. Dauerhaften Speicher anlegen und Deployment aktualisieren:
|
||||
kubectl apply -f k8s/04-uploads-pvc.yaml
|
||||
kubectl apply -f k8s/05-app-deployment.yaml
|
||||
|
||||
# 3. Gegenprobe — jetzt muss dort ein persistentVolumeClaim stehen:
|
||||
kubectl get deployment wabenhain-app -n wabenhain -o jsonpath='{.spec.template.spec.volumes[?(@.name=="uploads")]}{"
|
||||
"}'
|
||||
kubectl get pvc wabenhain-uploads -n wabenhain
|
||||
```
|
||||
|
||||
Danach ueberstehen Uploads jeden Redeploy. Bereits verlorene Dateien lassen
|
||||
sich nicht wiederherstellen — sie muessen einmalig neu hochgeladen werden.
|
||||
|
||||
Das Deployment nutzt dabei `strategy: Recreate` (siehe Abschnitt oben):
|
||||
ohne das bliebe der neue Pod beim Redeploy an einem
|
||||
`Multi-Attach error for volume` haengen, weil ein
|
||||
`ReadWriteOnce`-Claim nur an einen Pod gebunden sein kann.
|
||||
|
||||
**Kontrolle im laufenden Betrieb:** Das Admin-Dashboard gleicht bei jedem
|
||||
Aufruf ab, ob die in der Datenbank hinterlegten Bild-/Videopfade als Dateien
|
||||
vorliegen, und zeigt sonst eine Warnung mit Anzahl und Beispielpfaden
|
||||
(`lib/upload-health.ts`). Dieser Fall faellt damit sofort auf, statt erst
|
||||
dann, wenn Kundschaft im Shop leere Flaechen sieht.
|
||||
|
||||
## Sicherung und Wiederherstellung
|
||||
|
||||
`07-backup-cronjob.yaml` legt jede Nacht um 03:15 Uhr eine
|
||||
|
||||
Reference in new issue
Block a user