· Kubernetes · 7 Min. Lesezeit
Zalando-Postgres-Operator: alle Stolpersteine im Überblick
Die vollständige Fallsammlung zum Zalando-Postgres-Operator. Gelöschte PVCs, ein Löschschutz der nicht blockiert, CRD-Konflikte mit ArgoCD, der Registry-Wechsel nach ghcr.io, entfallene Postgres-Versionen und der anstehende Wechsel der Leader-Wahl. Jeder Fall im Schema Symptom, Ursache, Prüfung, Lösung.

Diese Sammlung ist als Nachschlagewerk gedacht, nicht als Anleitung von vorn. Sie richtet sich an zwei Gruppen. An alle, die den Operator bereits betreiben und ein konkretes Symptom vor sich haben. Und an alle, die vor einem Upgrade oder vor der Übergabe an GitOps wissen wollen, was sie erwartet, bevor sie es erleben.
Alle Fälle beziehen sich auf den Stand v1.15.1 vom 18.12.2025. Der vollständige Einrichtungsweg mit den Schutzschaltern, die den ersten drei Fällen zugrunde liegen, steht im Hauptbeitrag Zalando-Postgres-Operator: adoptieren und die PVC-Falle.
1. Die Daten sind weg, obwohl die Retention-Policy auf retain stand
Symptom: Nach dem Entfernen der postgresql-Ressource ist der PersistentVolumeClaim verschwunden, obwohl die persistent_volume_claim_retention_policy des StatefulSets auf retain gesetzt war.
Ursache: Der Operator räumt die PVCs selbst auf und ignoriert dabei die Retention-Policy des StatefulSets. Die Parameter-Referenz sagt das ausdrücklich. enable_persistent_volume_claim_deletion ist per Default true. Die Dokumentation unterscheidet an dieser Stelle nicht danach, wodurch das Manifest entfernt wurde.
Prüfung:
kubectl get configmap postgres-operator \
-o jsonpath='{.data.enable_persistent_volume_claim_deletion}'Danach ein Testlöschen in einem Wegwerf-Namespace, gefolgt von:
kubectl get pvc -l application=spiloLösung: enable_persistent_volume_claim_deletion auf false setzen, bevor der erste produktive Cluster entsteht. Sinnvollerweise gleich enable_secrets_deletion mit, sonst überleben die Volumes und die Zugangsdaten dazu sind weg.
2. Der Löschschutz greift, die Ressource verschwindet trotzdem
Symptom: Die Annotationen sind konfiguriert und im Manifest gesetzt, aber kubectl delete pg entfernt die Ressource.
Ursache: Das ist dokumentiertes Verhalten. Der Operator weist den API-Server nicht an, das Löschen zu blockieren. Nur das Operator-Log meldet, dass das Löschkriterium nicht erfüllt war.
Prüfung:
kubectl logs -l name=postgres-operator | grep -i deletekubectl get pvc -l application=spilo,cluster-name=<name>Lösung: Kein Eingriff nötig. Weil die Kindressourcen inklusive PVC stehen bleiben, lässt sich der Cluster mit kubectl create aus demselben Manifest wiederherstellen. Die Dokumentation nennt das ausdrücklich als sicheren Weg nach einem versehentlichen Löschen. Wer zusätzlich die Ressource selbst schützen will, braucht Prune=false oder eine Admission-Policy. Beachten Sie dabei, dass die Dokumentation den Annotationsschutz für kubectl delete pg beschreibt. Ob er bei anderen Löschwegen gleich wirkt, steht dort nicht.
3. Der Löschschutz wirkt plötzlich nicht mehr
Symptom: Die Annotationen stehen unverändert im Manifest, der Schutz greift trotzdem nicht.
Ursache: enable_owner_references wurde eingeschaltet. Die Dokumentation warnt ausdrücklich, dass diese Option die konfigurierten Löschschutz-Prüfungen deaktiviert.
Prüfung:
kubectl get operatorconfiguration postgresql-operator-configuration \
-o jsonpath='{.configuration.kubernetes.enable_owner_references}'Lösung: Entscheiden Sie sich. Entweder Owner References aus lassen, das ist der Standard, und den Annotationsschutz nutzen. Oder Owner References einschalten und den Schutz bewusst allein auf Prune=false und Backups stützen. Beides zusammen funktioniert nicht. PVCs sind von den Owner References ausgenommen, ebenso der Patroni-Config-Service samt Endpoint und namespace-übergreifende Secrets.
4. Nach dem Helm-Upgrade werden Manifest-Felder abgelehnt
Symptom: Der Operator läuft in neuer Version, aber neue Felder im Cluster-Manifest werden zurückgewiesen oder verhalten sich falsch.
Ursache: Helm aktualisiert die CRDs Postgresql und OperatorConfiguration beim Chart-Update nicht mit. Es laufen dann neuer Operator und altes CRD-Schema gegeneinander.
Prüfung:
kubectl get crd postgresqls.acid.zalan.do -o yamlkubectl logs -l name=postgres-operatorLösung: Die vorgeschriebene Reihenfolge einhalten. Erst die CRDs aus dem Ordner crds des Repositories anwenden, danach das Chart aktualisieren.
5. ArgoCD und der Operator streiten um die CRDs
Symptom: Die Application bleibt dauerhaft OutOfSync, die CRDs ändern sich ohne erkennbaren Anlass.
Ursache: Der Operator registriert die CRDs beim Start selbst und aktualisiert sie. Werden dieselben CRDs zusätzlich von Helm oder ArgoCD verwaltet, schreiben zwei Instanzen dieselbe Ressource.
Prüfung:
kubectl get crd postgresqls.acid.zalan.do -o jsonpath='{.metadata.resourceVersion}'kubectl get operatorconfiguration postgresql-operator-configuration \
-o jsonpath='{.configuration.enable_crd_registration}'Lösung: enable_crd_registration auf false setzen und die CRDs sauber getrennt verwalten, oder die CRDs aus dem GitOps-Scope herausnehmen. Zwei Schreiber auf einer Ressource sind in beiden Richtungen falsch.
6. Die UI und der Logical-Backup-Job starten nicht
Symptom: Das Chart in Version v1.15.0 installiert sich, aber die Weboberfläche und der Logical-Backup-Job bleiben im Image-Pull hängen.
Ursache: Für v1.15.0 wurden keine Images für UI und Logical Backup veröffentlicht. Die Release-Notes verweisen deshalb direkt auf v1.15.1.
Prüfung:
kubectl get pods -l app.kubernetes.io/name=postgres-operator-uiLösung: v1.15.0 überspringen und gleich v1.15.1 nehmen.
7. Image-Pulls schlagen nach dem Update auf v1.15.1 fehl
Symptom: Nach dem Update ziehen Pods keine Images mehr, in den Referenzen steht registry.opensource.zalan.do.
Ursache: Ab v1.15.1 werden keine Images mehr in diese Registry gepusht. Die Images liegen unter ghcr.io/zalando/.
Prüfung:
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' \
| grep zalan.doLösung: Alle Image-Referenzen umstellen, also das Operator-Deployment, docker_image für Spilo und logical_backup_docker_image. Der obige Befehl darf danach keinen Treffer mehr liefern. Wer einen Pull-Through-Proxy betreibt, zieht die neue Quelle dort ebenfalls nach.
8. Postgres-12-Cluster starten nach dem Operator-Upgrade nicht mehr
Symptom: Nach dem Sprung auf v1.14.0 oder neuer kommen Cluster mit Postgres 12 nicht mehr hoch.
Ursache: v1.14.0 hat die Unterstützung für Postgres 12 entfernt. v1.15.1 deckt laut Kompatibilitätstabelle 13 bis 17 ab.
Prüfung:
kubectl get postgresql -A \
-o custom-columns=NAME:.metadata.name,VERSION:.spec.postgresql.versionLösung: Die Reihenfolge ist zwingend. Erst die Datenbanken auf eine unterstützte Major-Version heben, dann den Operator aktualisieren. Das In-Place-Upgrade steuert major_version_upgrade_mode mit den Werten off, manual oder full. Der Standard ist manual, minimal_major_version ist 13, target_major_version ist 17.
9. Das Major-Upgrade passiert nie
Symptom: target_major_version ist korrekt gesetzt, das Upgrade läuft trotzdem nicht an.
Ursache: Zwei Voraussetzungen sind dokumentiert, und ohne sie startet das Upgrade nicht. Erstens muss die Umgebungsvariable PGVERSION in den Datenbank-Pods gesetzt sein. Die zugehörige Option enable_pgversion_env_var ist seit v1.6.0 standardmäßig aktiv. Zweitens löst der Operator ein Major-Upgrade nur innerhalb der im Manifest definierten maintenanceWindows aus, und diese müssen laut Administrator-Dokumentation mindestens doppelt so lang sein wie die konfigurierte resync_period.
Prüfung:
kubectl exec $PGMASTER -- env | grep PGVERSIONDanach die maintenanceWindows im Manifest gegen die resync_period in der Operator-Konfiguration abgleichen.
Lösung: PGVERSION setzen und die Wartungsfenster ausreichend groß wählen. Manuell anstoßen lässt sich das Upgrade im Primary-Pod. Das Argument des Skripts ist die Anzahl der Cluster-Mitglieder aus numberOfInstances, nicht die Ziel-Major-Version:
python3 /scripts/inplace_upgrade.py NBei einem Cluster mit drei Instanzen lautet der Aufruf also python3 /scripts/inplace_upgrade.py 3. Wer hier die gewünschte Postgres-Version einsetzt, übergibt dem Skript eine falsche Mitgliederzahl.
10. Das Volume lässt sich nicht wieder verkleinern
Symptom: Eine reduzierte Größe im Manifest wird übernommen, das Volume bleibt aber groß.
Ursache: Der Operator kann Volumes nur vergrößern. Verkleinern wird nicht unterstützt und erzeugt lediglich eine Warnung.
Prüfung:
kubectl logs -l name=postgres-operatorkubectl get pvc -l application=spilo \
-o custom-columns=NAME:.metadata.name,SIZE:.spec.resources.requests.storageLösung: Die Größe von Anfang an konservativ wählen. Der einzige Weg zurück führt über einen Klon in einen neuen Cluster mit kleinerem Volume.
11. Die Leader-Wahl ändert sich künftig ohne Ihr Zutun
Symptom: Noch keins. Das ist eine angekündigte Änderung, die Sie jetzt entschärfen.
Ursache: kubernetes_use_configmaps steuert, ob Endpoints oder ConfigMaps für die Verwaltung des Leaders genutzt werden, wenn Kubernetes als DCS dient. Der aktuelle Standard ist false, also Endpoints. Die Parameter-Referenz kündigt an: ab v1.16.0 wird der Standard auf true geändert. Hintergrund ist, dass Endpoints ab Kubernetes 1.33 als deprecated markiert sind. Unter OpenShift ist die Endpoints-Variante ohnehin nicht nutzbar, dort sind ConfigMaps erforderlich.
Prüfung:
kubectl get operatorconfiguration postgresql-operator-configuration \
-o jsonpath='{.configuration.kubernetes.kubernetes_use_configmaps}'kubectl get endpoints,configmaps -l application=spiloLösung: Den Wert jetzt explizit setzen, statt sich auf den Default zu verlassen. Dann ändert ein künftiges Upgrade das Verhalten nicht hinter Ihrem Rücken. Für den Wechsel auf ConfigMaps nennt die Parameter-Referenz eine harte Bedingung: Skalieren Sie den Postgres-Cluster vorher auf einen einzigen Primary-Pod herunter, etwa über die Option max_instances. Andernfalls riskieren Sie ein Split-Brain-Szenario. Der Wechsel gehört damit in ein Wartungsfenster und nicht in einen laufenden Sync.
Der Weg dorthin
Die Reihenfolge, in der Sie diese Fälle am besten gar nicht erst erreichen, steht im Hauptbeitrag Zalando-Postgres-Operator: adoptieren und die PVC-Falle. Dort sind die Schutzschalter aus den Fällen 1 bis 3 vor der ersten Installation gesetzt, und dort steht auch, warum es keinen dokumentierten Weg gibt, eine bestehende Instanz zu übernehmen.
Sie betreiben Datenbanken und wollen sicher sein, dass die Daten einen Fehlgriff überleben? Ich baue Datenhaltung mit getestetem Backup und klarer Wiederherstellung, auf Kubernetes wie klassisch. Mehr unter Infrastruktur & Cloud, das Erstgespräch ist unverbindlich.

Alex Jabi
Ich betreue IT, Informationssicherheit und Datenschutz für KMU und Praxen an der Bergstraße und im Odenwald, persönlich, dokumentiert und ohne Cloud-Zwang.
Mehr über mich


