StatefulSets sind eine spezialisierte Controller-Ressource zur Verwaltung zustandsbehafteter Pods. Während Deployments ideal für zustandslose Anwendungen sind, bieten StatefulSets die notwendigen Garantien für Workloads mit dauerhaftem Zustand, die persistente Netzwerk- und Speicherzuordnungen erfordern.
Ein StatefulSet verwaltet Pods mit stabiler Identität und zugeordnetem Speicher für zustandsbehaftete Anwendungen, die folgende Eigenschaften benötigen:
| Merkmal | Deployment | StatefulSet |
|---|---|---|
| Pod-Namen | Zufällig generiert | Vorhersagbar (name-0, name-1, etc.) |
| Pod-Reihenfolge | Parallel | Sequenziell |
| Speicher | Ephemeral oder shared | Persistent pro Pod |
| Netzwerk-Identität | Unstabil | Stabil und vorhersagbar |
| Updateverhalten | Rolling, parallel | Rolling, sequentiell (oder OnDelete) |
| Typische Anwendungen | Zustandslose Apps | Datenbanken, verteilte Systeme |
Wichtiger Unterschied beim Pod-Management: Deployments ermöglichen automatisches Recreate von Pods mit neuen UIDs – StatefulSets hingegen erhalten die Pod-Identität durch fest zugewiesene PVCs und Hostnamen. Zwar werden Pods wie üblich neu erzeugt, behalten jedoch ihre logische Identität durch stabilen Namen und zugeordneten Speicher.
StatefulSets weisen jedem Pod eine ordinale Identität zu: -
myapp-0, myapp-1, myapp-2, etc. -
Diese Namen bleiben über Pod-Lebenszyklen hinweg stabil - Bei einem
Pod-Neustart erhält der neue Pod denselben Namen und dieselben PVCs
StatefulSets erfordern einen Headless Service (ClusterIP: None), der:
- Direkte DNS-Auflösung zu einzelnen Pods ermöglicht - Stabile
Netzwerk-Endpunkte bereitstellt - DNS-Namen im Format
pod-name.service-name.namespace.svc.cluster.local erstellt
- Keinen eigenen LoadBalancer oder ClusterIP bereitstellt, sondern
direkten DNS-Zugriff auf einzelne Pod-IPs ermöglicht
StatefulSets verwenden Volume Claim Templates für persistenten Speicher: - Jeder Pod erhält sein eigenes PersistentVolumeClaim - Volumes überleben Pod-Neustarts - Beim Skalieren des StatefulSets werden für neu erzeugte Pods automatisch neue PVCs erstellt - Wichtig: PVCs werden nur einmal pro Pod erzeugt und nicht automatisch gelöscht – auch nach Herunterskalierung bestehen sie fort. Automatische Garbage Collection erfolgt nur bei expliziter PVC-Löschung. Ein manuelles Löschen ungenutzter PVCs nach Downscaling kann automatisiert werden, z.B. über CronJob/Controller.
PVC-Namensgebung: Der erzeugte PVC folgt dem Schema
<claimName>-<statefulsetName>-<ordinal>,
z.B. mysql-storage-mysql-0
Hier ist ein vollständiges Beispiel für ein MySQL StatefulSet:
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
labels:
app: mysql
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_DATABASE
value: "mydb"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
- name: config
mountPath: /etc/mysql/conf.d
volumes:
- name: config
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: mysql-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
storageClassName: fast-ssdapiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
password: cGFzc3dvcmQxMjM= # base64 kodiert: "password123"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
server-id=1
log-bin=mysql-bin
binlog-format=rowkubectl scale statefulset mysql --replicas=5Verhalten: - Neue Pods werden sequenziell erstellt: mysql-3, dann mysql-4 - Jeder Pod wartet, bis der vorherige bereit ist - Neue PVCs werden automatisch erstellt
kubectl scale statefulset mysql --replicas=2Verhalten: - Pods werden in umgekehrter Reihenfolge gelöscht: mysql-4, dann mysql-3 - PVCs bleiben erhalten für mögliche spätere Wiederverwendung
Im Gegensatz zu Deployments erfolgen Updates nicht parallel, sondern geordnet gemäß Ordinalität der Pods.
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0partition: 2 bedeutet, dass Pods mit höherem Index als 1
(also mysql-2, mysql-3, …) aktualisiert
werden, während mysql-0 und mysql-1
unangetastet bleiben. Nützlich z.B. für Canary-Upgrades oder gestaffelte
Migrationen.spec:
updateStrategy:
type: OnDeletekubectl get pods -l app=mysql
kubectl describe statefulset mysqlkubectl get pvc
kubectl describe pvc mysql-storage-mysql-0kubectl logs mysql-0
kubectl logs mysql-0 --previous # Vorherige Pod-InstanzapiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: mysql-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: mysqlEviction Handling: Pod Disruption Budgets sind besonders wichtig für Eviction Handling durch Cluster-Autoscaler oder bei Node-Drains, da sie ungewollte Downtime verhindern.
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- mysql
- -h
- 127.0.0.1
- -e
- "SELECT 1"
initialDelaySeconds: 5
periodSeconds: 2Kritischer Hinweis: Falsch konfigurierte Probes sind bei StatefulSets besonders kritisch, da ein einzelner fehlerhafter Pod nachfolgende Instanzen blockieren kann und die sequenzielle Natur der StatefulSets beeinträchtigt.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
fsType: ext4
encrypted: "true"
volumeBindingMode: WaitForFirstConsumerVolume Binding Mode:
volumeBindingMode: WaitForFirstConsumer ist essenziell für
Pod Scheduling bei StatefulSets mit lokalem Storage, da das Volume erst
gebunden wird, wenn der Pod auf einem Node geplant wird.
Symptom: Pod verbleibt im Status Pending oder Init
Diagnose:
kubectl describe pod mysql-0
kubectl get events --field-selector involvedObject.name=mysql-0Häufige Ursachen und Lösungen: - PVC kann nicht gebunden werden → Storage Class und verfügbare PVs prüfen - Insufficient resources → Node-Kapazitäten überprüfen - Image pull errors → Registry-Zugriff und Image-Namen validieren - ConfigMap/Secret nicht verfügbar → Abhängigkeiten prüfen
Symptom: Neue Pods werden nicht erstellt trotz Scale-Befehl
Diagnose:
kubectl get pod mysql-2 -o yaml
kubectl describe statefulset mysqlMögliche Probleme und Lösungen: - Vorheriger Pod nicht bereit → Readiness Probe und Pod-Logs prüfen - Insufficient storage → PVC-Status und Storage Class überprüfen - Node capacity limits → Cluster-Ressourcen analysieren
Symptom: Persistente Daten sind nach Pod-Neustart nicht verfügbar
Diagnose und Überprüfung:
kubectl get pvc mysql-storage-mysql-0
kubectl describe pv <pv-name>Lösungsansätze: - PVC korrekt gemountet? → Pod-Beschreibung und Mount-Points prüfen - Storage Class verfügbar? → StorageClass-Status validieren - Persistent Volume provisioniert? → PV-Status und Binding überprüfen
Für bestimmte Anwendungen kann parallele Pod-Verwaltung aktiviert werden:
spec:
podManagementPolicy: ParallelWichtige Warnung: Verwenden Sie dies NICHT bei Clustern mit Start-Up-Dependencies (z.B. Master-Follower-Konfigurationen), da die Reihenfolge für ordnungsgemäße Initialisierung kritisch ist.
StatefulSets können mit Operatoren erweitert werden für: - Automatisches Backup - Disaster Recovery - Advanced Health Checking - Custom Scaling Logic
DaemonSets: Stellen sicher, dass genau ein Pod auf jedem Node läuft – häufig genutzt für Logging, Monitoring oder Netzwerkdienste.
Deployments: Verwalten zustandslose Anwendungen ohne persistente Identität oder Speicherzuordnung.
StatefulSets: Für zustandsbehaftete Anwendungen mit persistenter Identität, geordneter Pod-Verwaltung und stabilen Speicherzuordnungen – ideal für Datenbanken und Cluster-Services.
PVCs aus StatefulSets können – je nach StorageClass – nachträglich
erweitert werden, z.B. durch Patchen des
resources.requests.storage-Feldes. Der StorageClass-Treiber
muss Volume Expansion (allowVolumeExpansion: true)
unterstützen, was bei Cloud-Provisionern oft Standard ist. Dies
ermöglicht dynamische Speichererweiterung ohne Pod-Neustart bei
unterstützten Storage-Backends.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-netpol
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: webapp
ports:
- protocol: TCP
port: 3306spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 999
fsGroup: 999
containers:
- name: mysql
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALLHinweis zu Pod Security: In Kubernetes ≥1.25 sind PodSecurityAdmission oder OPA Gatekeeper als Nachfolger der Pod Security Policies gebräuchlich.