StatefulSets & Persistent Storage in Kubernetes
Stateful apps implementeren met geordende schaalbaarheid & persistente gegevens
Kubernetes StatefulSets zijn de voorkeur oplossing voor het beheren van toepassingen met staat, die stabiele identiteiten, persistente opslag en geordende implementatiemodellen vereisen—essentieel voor databases, gedistribueerde systemen en cachinglagen.
Als je nieuw bent in Kubernetes of een cluster instelt, overweeg dan het verkennen van Kubernetes distributies zoals k3s of MicroK8s voor ontwikkeling, of het installeren van Kubernetes met Kubespray voor productieklare clusters.
Deze mooie afbeelding is gegenereerd door AI model Flux 1 dev.
Wat zijn StatefulSets?
StatefulSets zijn een Kubernetes werkbelasting API-object dat specifiek is ontworpen voor het beheren van toepassingen met staat. In tegenstelling tot Deployments die alle pods als vervangbaar beschouwen, behouden StatefulSets een unieke identiteit voor elke pod met garanties over volgorde en uniekheid.
Belangrijke kenmerken:
- Stabiele netwerkidentiteiten: Elke pod krijgt een voorspelbare hostnaam die blijft bestaan na herstarts
- Persistente opslag: Afgestane PersistentVolumeClaims die pods volgen bij herschakelingen
- Geordende implementatie: Pods worden opeenvolgend aangemaakt (0, 1, 2…) en worden in omgekeerde volgorde beëindigd
- Geordende updates: Rolling updates verlopen in volgorde, wat de toepassingsstabiliteit waarborgt
StatefulSets zijn essentieel voor toepassingen zoals PostgreSQL, MySQL, MongoDB, Cassandra, Elasticsearch, Kafka, ZooKeeper, Redis en etcd—elke werklast waarbij de podidentiteit en datapersistente belangrijk zijn.
Begrijpen van persistente opslag in Kubernetes
Kubernetes biedt een geavanceerde opslagabstractielayer die de beheer van opslag loskoppelt van de podlevenscyclus:
Opslagcomponenten
PersistentVolume (PV): Een stuk opslag in het cluster dat door een administrator is aangemaakt of dynamisch is gegenereerd via een StorageClass. PVs bestaan onafhankelijk van pods.
PersistentVolumeClaim (PVC): Een verzoek naar opslag door een pod. PVCs binden aan beschikbare PVs die overeenkomen met hun eisen (grootte, toegangsmodus, storageclass).
StorageClass: Definieert verschillende “klassen” van opslag met verschillende provisioners (AWS EBS, GCE PD, Azure Disk, NFS, enz.) en parameters zoals replicatie, prestatieniveaus en back-upbeleid.
Toegangsmodi
- ReadWriteOnce (RWO): Volume gemount als lees-schrijf door één knooppunt
- ReadOnlyMany (ROX): Volume gemount als alleen-lezen door meerdere knooppunten
- ReadWriteMany (RWX): Volume gemount als lees-schrijf door meerdere knooppunten (vereist speciale opslagback-ends)
StatefulSet-opslagarchitectuur
StatefulSets gebruiken volumeClaimTemplates om automatisch PersistentVolumeClaims aan te maken voor elke pod replica. Dit is fundamenteel anders dan Deployments:
Hoe volumeClaimTemplates werken
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-ssd"
resources:
requests:
storage: 10Gi
Wanneer je deze StatefulSet aanmaakt:
- Kubernetes maakt pod
mysql-0en PVCdata-mysql-0 - Vervolgens maakt Kubernetes pod
mysql-1en PVCdata-mysql-1 - Tot slot maakt Kubernetes pod
mysql-2en PVCdata-mysql-2
Elke pod krijgt zijn eigen afgestane 10GB persistente volume. Als mysql-1 wordt verwijderd of herschakeld, maakt Kubernetes deze opnieuw aan en koppelt hetzelfde data-mysql-1 PVC aan, waardoor alle gegevens behouden blijven.
Het aanmaken van een headless service voor StatefulSets
StatefulSets vereisen een headless service om stabiele netwerkidentiteiten te bieden:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
clusterIP: None # Dit maakt het een headless service
selector:
app: mysql
ports:
- port: 3306
name: mysql
Dit maakt DNS-entries voor elke pod:
mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local
Toepassingen kunnen rechtstreeks verbinding maken met specifieke podinstanties via deze stabiele DNS-namen.
StatefulSet-implementatiemodellen
Voor teams die complexe Kubernetes-implementaties beheren, bieden Helm Charts een krachtige manier om StatefulSets te verpakken en te implementeren met sjablonering, versiebeheer en afhankelijkheidsbeheer. Helm vereenvoudigt het beheren van StatefulSet-configuraties over verschillende omgevingen.
Geordende schaalbaarheid
Bij het schalen van 3 naar 5 replica’s:
kubectl scale statefulset mysql --replicas=5
Kubernetes maakt pods in volgorde: mysql-3 → wacht op Ready → mysql-4
Bij het schalen van 5 naar 3 replica’s:
kubectl scale statefulset mysql --replicas=3
Kubernetes beëindigt in omgekeerde volgorde: mysql-4 → wacht op beëindiging → mysql-3
Rolling updates
StatefulSets ondersteunen twee updatestrategieën:
OnDelete: Handmatige updates—pods worden alleen bijgewerkt wanneer je ze verwijdert RollingUpdate: Automatische opeenvolgende updates in omgekeerde volgorde
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Alleen bijwerken van pods met ordinal >= 2
De partition-parameter maakt canary-implementaties mogelijk—je kunt eerst hoge-nummerde pods bijwerken en testen voordat je ze uitbreidt naar alle replica’s.
Opslagbest practices
Dynamische provisioning
Gebruik altijd StorageClasses voor dynamische volumeprovisionering:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
allowVolumeExpansion: true
reclaimPolicy: Retain
allowVolumeExpansion: Schakelt het vergroten van PVCs uit zonder ze opnieuw aan te maken
reclaimPolicy: Retain houdt PV-gegevens na PVC-verwijdering vast, Delete verwijdert ze automatisch
PVC-retentiebeleid
Kubernetes 1.23+ ondersteunt persistentVolumeClaimRetentionPolicy:
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # Houd PVCs vast wanneer StatefulSet wordt verwijderd
whenScaled: Delete # Verwijder PVCs wanneer geschaald wordt
Opties:
- Retain: Houd PVCs vast (standaardgedrag, veiligst)
- Delete: Verwijder PVCs automatisch (handig voor ontwikkelomgevingen)
Back-upstrategieën
Volume snapshots: Gebruik VolumeSnapshot-resources om punt-in-tijd-back-ups aan te maken
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-snapshot-20251113
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: data-mysql-0
Toepassingsniveau back-ups: Gebruik tools zoals mysqldump, pg_dump of Velero voor back-ups van databases
Gedistribueerde replicatie: Stel toepassingsniveau replicatie in (MySQL replicatie, PostgreSQL streaming replicatie) als eerste verdedigingslinie
Reële toepassingsgevallen
Databasecluster (PostgreSQL)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard"
resources:
requests:
storage: 20Gi
Gedistribueerde cache (Redis)
Voor Redis clusters heb je zowel een StatefulSet als zorgvuldige configuratie nodig:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis-service
replicas: 6
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- "--appendonly"
- "yes"
- "--appendfsync"
- "everysec"
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
Berichtenwachtrij (Kafka)
Kafka vereist zowel persistente opslag voor logboeken als stabiele netwerkidentiteiten voor coördinatie van brokers:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
spec:
serviceName: kafka-service
replicas: 3
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: confluentinc/cp-kafka:7.5.0
ports:
- containerPort: 9092
name: kafka
env:
- name: KAFKA_BROKER_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: data
mountPath: /var/lib/kafka/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
Monitoring en probleemoplossing
Voor een uitgebreid overzicht van Kubernetes-commands gebruikt in deze sectie, zie de Kubernetes Cheatsheet.
Controleer StatefulSet-status
# Bekijk StatefulSet details
kubectl get statefulset mysql
kubectl describe statefulset mysql
# Controleer de aanmaakvolgorde en status van pods
kubectl get pods -l app=mysql -w
# Bekijk PVC-status
kubectl get pvc
kubectl describe pvc data-mysql-0
Algemene problemen
Pod vastgelopen in pending: Controleer PVC-status en opslagbeschikbaarheid
kubectl describe pod mysql-0
kubectl get events --sort-by='.lastTimestamp'
Opslag vol: Verwijder PVC als StorageClass dat toestaat
kubectl patch pvc data-mysql-0 -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
Pod wil niet beëindigen: Controleer op toepassingsniveau vergrendelingen of volume-afkoppelingproblemen
kubectl delete pod mysql-0 --grace-period=0 --force
Metrieken om te monitoren
- Opslaggebruik: Monitor PVC-capaciteit en gebruikspersentage
- I/O-prestaties: Volg IOPS, doorvoer en latentie
- Podherstarts: Veel herstarts kunnen wijzen op opslagproblemen
- PVC-bindtijd: Snel binden wijst op provisioningproblemen
Migratiestrategieën
Bij migratie naar StatefulSets, zorg er dan voor dat je Kubernetes-cluster correct is geconfigureerd. Voor homelab- of kleine clusteropstellingen, bekijk dan onze uitgebreide vergelijking van Kubernetes-distributies om het juiste platform te kiezen voor je werklastvereisten.
Van Deployment naar StatefulSet
- Maak een StatefulSet met volumeClaimTemplates
- Schaal Deployment af op een vlotte manier
- Herstel gegevens van back-ups naar StatefulSet-pods
- Bijwerken van DNS/service-verwijzingen
- Verwijder oude Deployment en PVCs
Back-up voor migratie
# Snapshot van bestaande PVCs
kubectl get pvc -o yaml > pvc-backup.yaml
# Maak volume snapshots
kubectl apply -f volume-snapshot.yaml
Beveiligingsoverwegingen
Opslagversleuteling
Schakel versleuteling in met StorageClass-parameters:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: encrypted-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
encrypted: "true"
kmsKeyId: arn:aws:kms:us-east-1:123456789012:key/abcd-1234
Toegangscontrole
Gebruik RBAC om wie kan maken/veranderen StatefulSets en PVCs:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: statefulset-manager
rules:
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get", "list", "create", "update", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "create", "delete"]
Netwerkbeleid
Beperk pod-naar-pod communicatie:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-network-policy
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 3306
Prestatieoptimalisatie
Opslagprestatieniveaus
Kies geschikte StorageClasses op basis van werklast:
- Hoog IOPS: Databases met zware willekeurige lees/schrijf (gp3, io2)
- Hoog doorvoer: Logaggregatie, analytics (st1, sc1)
- Balans: Algemene doeleinden (gp3)
Podverdeling
Gebruik pod-anti-affinity om StatefulSet-pods over beschikbaarheidszones te verspreiden:
spec:
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
topologyKey: topology.kubernetes.io/zone
Resourceaanvragen en limieten
Stel geschikte resources in voor consistente prestaties:
resources:
requests:
cpu: "2"
memory: "4Gi"
ephemeral-storage: "10Gi"
limits:
cpu: "4"
memory: "8Gi"
ephemeral-storage: "20Gi"
Geavanceerde patronen
Stateful toepassing met init-containers
Gebruik init-containers voor databaseinitialisatie:
spec:
template:
spec:
initContainers:
- name: init-mysql
image: mysql:8.0
command:
- bash
- "-c"
- |
if [[ ! -d /var/lib/mysql/mysql ]]; then
mysqld --initialize-insecure --datadir=/var/lib/mysql
fi
volumeMounts:
- name: data
mountPath: /var/lib/mysql
Multi-container pods voor sidecars
Voeg back-upsidecars of monitoringagents toe:
spec:
template:
spec:
containers:
- name: mysql
image: mysql:8.0
# ... mysql config ...
- name: backup-sidecar
image: mysql-backup:latest
volumeMounts:
- name: data
mountPath: /var/lib/mysql
readOnly: true
ConfigMaps voor dynamische configuratie
Scheid configuratie van StatefulSet-definitie:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
max_connections=200
innodb_buffer_pool_size=2G
---
spec:
template:
spec:
containers:
- name: mysql
volumeMounts:
- name: config
mountPath: /etc/mysql/conf.d
volumes:
- name: config
configMap:
name: mysql-config
Nuttige links
- Kubernetes StatefulSets Documentatie
- Persistent Volumes
- Storage Classes
- Volume Snapshots
- StatefulSet Best Practices
- CSI Drivers
- Velero Backup Oplossingen
- Rook Ceph Opslag
- Kubernetes Cheatsheet
- Install Kubernetes met Kubespray
- Vergelijking van Kubernetes distributies voor een 3-knooppunts homelab
- Kubernetes distributies - snelle overzicht van kubeadm, k3s, MicroK8s, Minikube, Talos Linux en RKE2
- Master Helm Charts: Kubernetes Package Management Guide