- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
StatefulSets geben Pods stabile Hostnamen und persistenten Storage — genau das, was Datenbanken brauchen. Mit Headless Services, PersistentVolumeClaims und einem pg_dump-CronJob betreibst du PostgreSQL auf Kubernetes produktionsreif. Managed Services sind trotzdem oft die bessere Wahl, wenn dein Team klein ist.
Datenbanken auf Kubernetes mit StatefulSets
Datenbanken auf Kubernetes waren lange ein Tabu. Mittlerweile gibt es gute Gründe dafür — und gute Gründe dagegen. Dieser Guide zeigt dir, wie du PostgreSQL mit einem StatefulSet aufsetzt und wann du besser die Finger davon lässt.
Prüfe zuerst, ob dein Cluster StorageClasses bereitstellt:
kubectl get storageclasses
kubectl get pv
Ohne dynamisches Provisioning funktionieren StatefulSets nicht sinnvoll.
StatefulSet vs Deployment
Ein Deployment behandelt alle Pods als austauschbar. Für einen Webserver ist das perfekt. Für eine Datenbank ist es fatal.
| Eigenschaft | Deployment | StatefulSet |
|---|---|---|
| Pod-Name | Zufällig (app-7f8d4) | Stabil (postgres-0, postgres-1) |
| Startreihenfolge | Parallel | Sequentiell (0, 1, 2...) |
| Storage | Shared oder keiner | Eigenes PVC pro Pod |
| DNS | Über Service-ClusterIP | Individuell pro Pod |
| Löschverhalten | Pods beliebig ersetzbar | PVCs bleiben erhalten |
Der stabile Hostname ist entscheidend: postgres-0 bleibt immer postgres-0, auch nach einem Neustart. Replikation und Clustering setzen das voraus.
Headless Service einrichten
StatefulSets brauchen einen Headless Service (ohne ClusterIP). Dieser erzeugt DNS-Einträge für jeden einzelnen Pod:
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
namespace: database
labels:
app: postgres
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
name: postgresql
Damit erreichst du jeden Pod direkt: postgres-0.postgres-headless.database.svc.cluster.local.
PostgreSQL StatefulSet
Hier das vollständige StatefulSet mit PersistentVolumeClaim-Template:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: database
spec:
serviceName: postgres-headless
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: appdb
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
livenessProbe:
exec:
command: ["pg_isready", "-U", "$(POSTGRES_USER)"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["pg_isready", "-U", "$(POSTGRES_USER)"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
Wichtig ist volumeClaimTemplates: Jeder Pod bekommt ein eigenes PVC. Wird der Pod gelöscht, bleibt das PVC bestehen — die Daten überleben.
Erstelle vorher das Secret:
kubectl create namespace database
kubectl create secret generic postgres-credentials \
-n database \
--from-literal=username=appuser \
--from-literal=password=$(openssl rand -base64 24)
Backup mit pg_dump CronJob
Ohne Backup ist deine Datenbank wertlos. Ein CronJob sichert PostgreSQL täglich:
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
namespace: database
spec:
schedule: "0 3 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: pg-dump
image: postgres:16-alpine
command:
- /bin/sh
- -c
- |
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
pg_dump -h postgres-0.postgres-headless \
-U $PGUSER -d appdb \
--format=custom \
-f /backups/appdb-${TIMESTAMP}.dump
# Backups älter als 7 Tage löschen
find /backups -name "*.dump" -mtime +7 -delete
env:
- name: PGUSER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
volumeMounts:
- name: backup-volume
mountPath: /backups
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: postgres-backups
Der CronJob läuft jeden Tag um 03:00 Uhr und behält Backups für 7 Tage.
Wann Kubernetes-Datenbanken Sinn machen
Nicht jede Datenbank gehört auf Kubernetes. Hier eine ehrliche Einschätzung:
Kubernetes eignet sich für Datenbanken, wenn:
- Dein Team Kubernetes-Erfahrung hat und Operatoren versteht
- Du eine einheitliche Deployment-Pipeline willst (GitOps)
- Du On-Premises arbeitest ohne Zugang zu Managed Services
- Dev/Staging-Umgebungen, die Production nachbilden sollen
Managed Services sind besser, wenn:
- Dein Team keine Erfahrung mit Storage und StatefulSets hat
- High Availability und automatische Failover nötig sind
- Du in einer Cloud arbeitest (RDS, Cloud SQL, Azure Database)
- Compliance-Anforderungen professionelle Wartung verlangen
Für Production auf Kubernetes empfehlen sich Operatoren wie CloudNativePG oder Zalando Postgres Operator — sie automatisieren Failover, Replikation und Backups.
FAQ
Überleben meine Daten einen Pod-Neustart?
Ja. Das PVC ist vom Pod-Lifecycle entkoppelt. Selbst wenn du den Pod löschst, bleibt das PersistentVolume mit den Daten bestehen. Erst wenn du das PVC explizit löschst, werden die Daten freigegeben.
Kann ich PostgreSQL auf mehrere Replicas skalieren?
Technisch ja — setze replicas: 3. Aber PostgreSQL unterstützt kein Multi-Master nativ. Du brauchst Streaming Replication oder einen Operator wie CloudNativePG, der Primary/Replica-Topologie automatisch verwaltet.
Was passiert bei einem Node-Ausfall?
Kubernetes startet den Pod auf einem anderen Node. Das PVC wird vom alten Node detached und am neuen Node attached. Bei Cloud-Storage (EBS, Persistent Disk) dauert das 1-3 Minuten. Bei lokalem Storage (local-path) gehen die Daten verloren.
Wie überwache ich die Datenbank-Performance?
Deploye den postgres-exporter als Sidecar-Container im StatefulSet. Er exportiert PostgreSQL-Metriken im Prometheus-Format. Kombiniere das mit Grafana-Dashboards für Verbindungen, Query-Laufzeiten und Cache-Hit-Ratios.
Nächster Schritt: Du brauchst Unterstützung bei der Migration deiner Datenbanken auf Kubernetes oder willst wissen, ob sich StatefulSets für deinen Use Case lohnen?
Legacy zu Kubernetes migrieren?
Wir begleiten Ihre Migration von VMs zu Containern – ohne Produktionsausfall. Erfahrung aus 50+ Migrationsprojekten.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
PostgreSQL Operator: CloudNativePG vs. Crunchy vs. Zalando
Drei PostgreSQL-Operatoren für Kubernetes im praktischen Vergleich: Features, Failover-Verhalten und Backup-Strategien für produktionsreife Deployments.
Kubernetes pgvector: PostgreSQL als performanten Vector Store implementieren
Erfahren Sie, wie Sie pgvector nutzen, um PostgreSQL auf Kubernetes als performanten und datenschutzkonformen Vector Store für KI-Anwendungen im deutschen Mittelstand zu etablieren. Profitieren Sie von einer zukunftssicheren hybriden Datenarchitektur, die lokalen Anforderungen gerecht wird.
Velero Backup: Kubernetes-Cluster richtig sichern
Velero für Kubernetes einrichten: Installation, Backup-Schedules, Namespace- und Cluster-Backups, Restore-Prozeduren und DR-Tests.
Disaster Recovery für Kubernetes-Cluster planen
Kubernetes Disaster Recovery planen: Von etcd-Backups über Multi-Cluster-Failover bis zur DR-Teststrategie mit konkreten Befehlen.
etcd Backup und Wartung: Kubernetes-Datenbank sichern
etcd-Backups mit etcdctl erstellen, automatisierte CronJobs einrichten und Snapshots fuer Disaster Recovery nutzen. Praxisanleitung fuer Cluster-Admins.