Postgres mit CloudNativePG betreiben
Die meisten echten Anwendungen brauchen Postgres – und es auf Kubernetes gut zu betreiben war lange das Argument dagegen, es überhaupt auf Kubernetes zu betreiben. CloudNativePG (CNPG) hat das geändert: ein CNCF-Operator, der PostgreSQL-Cluster deklarativ verwaltet – Provisionierung, Replikation, Failover, Backups – aus einem kurzen Manifest. Dieser Guide führt dich von null zu einer gesicherten Datenbank, die deine App nutzen kann. Die Schritte funktionieren auf jedem konformen Cluster; als Beispiel dient ein PaaSbox-Cluster.
Was du brauchst
Abschnitt betitelt „Was du brauchst“- Einen Cluster und seine kubeconfig – der Quickstart bringt dich in zehn Minuten dorthin.
kubectllokal installiert.- Für den Backup-Abschnitt: einen S3-kompatiblen Bucket samt Access-Keys – Hetzner Object Storage passt hier gut (es liegt an denselben Standorten wie dein Cluster und landet auf deiner eigenen Hetzner-Rechnung), genauso wie jeder andere S3-kompatible Speicher.
1. Operator installieren (einmal pro Cluster)
Abschnitt betitelt „1. Operator installieren (einmal pro Cluster)“kubectl apply --server-side -f \ https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases/cnpg-1.30.0.yamlDas installiert den Operator in cnpg-system (Release 1.30, Stand: 2026-07-09 – die aktuelle
Version findest du bei den
CNPG-Releases). Ab jetzt sind
Postgres-Cluster einfach Kubernetes-Ressourcen.
2. Eine Datenbank mit einer Instanz (Dev, Staging)
Abschnitt betitelt „2. Eine Datenbank mit einer Instanz (Dev, Staging)“Speichere als pg.yaml – genau in dieser Form startet eine kleine App:
apiVersion: postgresql.cnpg.io/v1kind: Clustermetadata: name: pg namespace: myappspec: instances: 1 # A zero-eviction PDB would block node drains and protects nothing with a # single replica. Re-enable (the default) when instances > 1. enablePDB: false bootstrap: initdb: database: myapp owner: myapp storage: size: 2Gi resources: requests: cpu: 100m memory: 256Mi limits: memory: 512Mikubectl create namespace myappkubectl apply -f pg.yamlkubectl -n myapp wait --for=condition=Ready cluster/pg --timeout=300sDas 2-Gi-Volume wird als Hetzner-Volume in deinem Projekt provisioniert – es erscheint auf deiner
Hetzner-Rechnung, lässt sich online vergrößern, wenn du storage.size änderst, und überdauert
den Ruhezustand – deine Daten überleben also einen schlafenden Cluster.
3. Deine Anwendung anbinden
Abschnitt betitelt „3. Deine Anwendung anbinden“CNPG erzeugt alles, was deine App braucht. Für einen Cluster namens pg bekommst du die Services
pg-rw (Primary, Read-Write) und pg-ro (Replicas, Read-Only) sowie ein Secret pg-app mit
fertigen Zugangsdaten – inklusive eines uri-Keys der Form
postgresql://myapp:…@pg-rw.myapp:5432/myapp. Die meisten Frameworks können das direkt verwenden:
env: - name: DATABASE_URL valueFrom: secretKeyRef: name: pg-app key: uriKein Passwort-Handling, kein manuell angelegtes Secret – der Operator besitzt und rotiert die Zugangsdaten.
4. Hochverfügbarkeit: drei Instanzen
Abschnitt betitelt „4. Hochverfügbarkeit: drei Instanzen“Für die Produktion änderst du eine einzige Zahl:
spec: instances: 3CNPG betreibt einen Primary und zwei Streaming-Replicas, verteilt sie über die Nodes und führt
automatisch ein Failover durch, wenn der Node des Primary ausfällt – der Service pg-rw zeigt
immer auf den aktuellen Primary, an deiner App ändert sich nichts. Entferne die Zeile
enablePDB: false (das Standard-PodDisruptionBudget schützt dich jetzt bei Node-Drains) und
stelle sicher, dass der Cluster mindestens drei einplanbare Worker hat – siehe
Workloads skalieren und autoskalieren.
5. Backups auf S3-kompatiblen Storage
Abschnitt betitelt „5. Backups auf S3-kompatiblen Storage“Volumes schützen vor Pod-Neustarts, nicht vor DROP TABLE. CNPG macht kontinuierliches
WAL-Archiving plus geplante Basis-Backups in den Object Storage. Lege ein Secret mit den
Zugangsdaten deines Buckets an und ergänze dann den Backup-Abschnitt:
kubectl -n myapp create secret generic pg-backup-creds \ --from-literal=ACCESS_KEY_ID=<your-access-key> \ --from-literal=ACCESS_SECRET_KEY=<your-secret-key>spec: backup: barmanObjectStore: destinationPath: s3://my-backup-bucket/pg endpointURL: https://nbg1.your-objectstorage.com # your S3-compatible endpoint s3Credentials: accessKeyId: name: pg-backup-creds key: ACCESS_KEY_ID secretAccessKey: name: pg-backup-creds key: ACCESS_SECRET_KEY retentionPolicy: 30dPlane anschließend ein nächtliches Basis-Backup:
apiVersion: postgresql.cnpg.io/v1kind: ScheduledBackupmetadata: name: pg-nightly namespace: myappspec: cluster: name: pg schedule: "0 0 3 * * *" # 03:00 daily (six-field cron, seconds first)Weil das WAL-Archiving zwischen den Basis-Backups durchgehend läuft, bekommst du
Point-in-Time-Recovery: Ein neues Cluster-Manifest mit einem bootstrap.recovery-Abschnitt
stellt jeden beliebigen Zeitpunkt innerhalb deines Aufbewahrungsfensters wieder her – das lohnt
sich einmal zu proben, bevor du es im Ernstfall brauchst.
Was du jetzt hast
Abschnitt betitelt „Was du jetzt hast“Ein deklaratives Postgres mit automatischem Failover, Zugangsdaten, die deine App aus einem Secret liest, und Backups außerhalb des Clusters mit Point-in-Time-Recovery – die Checkliste, die früher die Rechnung für eine Managed Database gerechtfertigt hat. Was dir bleibt, ist die Semantik: Schema-Migrationen, Datenqualität und das Testen des Restore-Pfads. (Die Plattform sichert die Control Plane deines Clusters; deine Datenbankinhalte sind genau die Art Anwendungsdaten, deren Schutz bei dir liegt – und dieses Setup ist der Weg dazu.)
Wie das in einer vollständigen Anwendung aussieht, zeigt der Guide Ein Django-SaaS deployen – er nutzt exakt dieses CNPG-Muster als Datenbank-Schicht.
Aufräumen
Abschnitt betitelt „Aufräumen“kubectl delete namespace myapp # removes the cluster and its volumes (backups in the bucket remain)