Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

StatefulSets Kubernetes : identité stable et stockage persistant

17 min de lecture

logo kubernetes

Un StatefulSet gère des Pods avec une identité stable, un stockage persistant dédié et un ordre de déploiement garanti. Contrairement à un Deployment où les Pods sont interchangeables, chaque Pod d’un StatefulSet conserve son nom, son réseau et son stockage même après un redémarrage.

Ce guide couvre la création, le headless Service, les volumeClaimTemplates, les stratégies de mise à jour et le scaling — tout ce qu’il faut pour la certification CKAD.

  • Créer un StatefulSet avec un headless Service
  • Configurer le stockage persistant avec volumeClaimTemplates
  • Comprendre le DNS stable des Pods StatefulSet
  • Mettre à jour un StatefulSet avec RollingUpdate et partitions
  • Choisir entre Deployment, StatefulSet et DaemonSet

Un StatefulSet est conçu pour les applications qui nécessitent :

BesoinExemple
Identité réseau stableChaque Pod garde son nom (app-0, app-1)
Stockage persistant dédiéChaque Pod a son propre PVC
Ordre de déploiementapp-0 démarre avant app-1
Scaling ordonnéScale down en ordre inverse
ApplicationPourquoi StatefulSet
Bases de donnéesPostgreSQL, MySQL, MongoDB — chaque instance a ses données
Clusters distribuésetcd, Zookeeper, Kafka — identité stable pour l’élection
Caches répliquésRedis Cluster — nœuds avec rôles spécifiques
Queues de messagesRabbitMQ — identité stable pour le clustering

Un StatefulSet nécessite un headless Service pour fournir le DNS stable de chaque Pod.

Un headless Service se distingue d’un Service classique par clusterIP: None. Au lieu de load-balancer vers les Pods, il crée une entrée DNS pour chaque Pod.

headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
clusterIP: None # Headless Service
selector:
app: nginx
ports:
- port: 80
name: web

Appliquer :

Fenêtre de terminal
kubectl apply -f headless-service.yaml

Chaque Pod d’un StatefulSet obtient un nom DNS prévisible :

<nom-pod>.<service-headless>.<namespace>.svc.cluster.local

Exemple avec un StatefulSet web et un Service nginx dans le namespace default :

PodDNS complet
web-0web-0.nginx.default.svc.cluster.local
web-1web-1.nginx.default.svc.cluster.local
web-2web-2.nginx.default.svc.cluster.local

Ce DNS stable permet aux applications distribuées de joindre un pair précis, même après un redémarrage du Pod.

Voici un StatefulSet simple avec 3 réplicas Nginx et un volume persistant de 1 Go par Pod :

statefulset-nginx.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: nginx # Référence au headless Service
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi

Points clés :

ChampRôle
serviceName: nginxLie le StatefulSet au headless Service
replicas: 3Crée 3 Pods : web-0, web-1, web-2
volumeClaimTemplatesCrée un PVC dédié par Pod (www-web-0, www-web-1, etc.)

Appliquer :

Fenêtre de terminal
kubectl apply -f statefulset-nginx.yaml

Observer le déploiement ordonné :

Fenêtre de terminal
kubectl get pods -l app=nginx -w
# NAME READY STATUS RESTARTS AGE
# web-0 0/1 Pending 0 0s
# web-0 1/1 Running 0 3s
# web-1 0/1 Pending 0 0s # Démarre après web-0 Ready
# web-1 1/1 Running 0 3s
# web-2 0/1 Pending 0 0s # Démarre après web-1 Ready
# web-2 1/1 Running 0 3s

Vérifier les PVC créés :

Fenêtre de terminal
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# www-web-0 Bound pvc-xxx 1Gi RWO
# www-web-1 Bound pvc-yyy 1Gi RWO
# www-web-2 Bound pvc-zzz 1Gi RWO

Ces commandes sont essentielles pour l’examen CKAD.

Fenêtre de terminal
# Vue d'ensemble des StatefulSets
kubectl get sts
# Détails complets (événements, stratégie, réplicas)
kubectl describe sts web
# Pods du StatefulSet avec leurs nœuds
kubectl get pods -l app=nginx -o wide
# PVC associés
kubectl get pvc -l app=nginx
# État du rollout en cours
kubectl rollout status sts/web
# Historique des révisions
kubectl rollout history sts/web

Depuis un Pod du cluster, testez la résolution DNS :

Fenêtre de terminal
kubectl run dns-test --rm -it --image=busybox:1.37 -- nslookup web-0.nginx
# Server: 10.96.0.10
# Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
#
# Name: web-0.nginx
# Address 1: 10.244.1.5 web-0.nginx.default.svc.cluster.local

Kubernetes supporte deux stratégies de mise à jour pour les StatefulSets.

C’est la stratégie par défaut. Kubernetes met à jour les Pods un par un, en ordre inverse (du plus grand ordinal vers le plus petit).

spec:
updateStrategy:
type: RollingUpdate

Comportement :

  1. web-2 est mis à jour et doit devenir Ready
  2. Puis web-1 est mis à jour
  3. Puis web-0

Appliquer une mise à jour (par exemple changer l’image) :

Fenêtre de terminal
kubectl set image sts/web nginx=nginx:1.28

Suivre la progression :

Fenêtre de terminal
kubectl rollout status sts/web
# Waiting for partitioned roll out to finish: 0 out of 3 new pods have been updated...
# statefulset rolling update complete 3 pods...

Vous pouvez limiter la mise à jour aux Pods d’ordinal supérieur ou égal à une valeur avec partition. C’est utile pour les déploiements progressifs.

spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Seul web-2 sera mis à jour

Exemple : avec partition: 2 et 3 réplicas :

  • web-2 : reçoit la nouvelle spec
  • web-1 : garde l’ancienne spec
  • web-0 : garde l’ancienne spec

C’est une forme de canary deployment pour StatefulSet.

Avec OnDelete, Kubernetes ne met pas à jour automatiquement les Pods. Vous devez les supprimer manuellement pour qu’ils soient recréés avec la nouvelle spec.

spec:
updateStrategy:
type: OnDelete

Workflow :

Fenêtre de terminal
# 1. Modifier la spec du StatefulSet
kubectl apply -f statefulset-updated.yaml
# 2. Les Pods existants ne changent pas
# 3. Supprimer manuellement un Pod pour déclencher sa recréation
kubectl delete pod web-0
# 4. Le nouveau Pod est créé avec la nouvelle spec
Fenêtre de terminal
kubectl rollout undo sts/web

Par défaut, les Pods sont créés et supprimés de manière ordonnée. Vous pouvez changer ce comportement avec podManagementPolicy.

Les Pods sont créés un par un, chaque Pod devant être Ready avant de créer le suivant. Lors du scale down, les Pods sont supprimés en ordre inverse.

spec:
podManagementPolicy: OrderedReady # Par défaut

Cas d’usage : applications où l’ordre de démarrage est critique (bases de données distribuées, clusters avec élection de leader).

Les Pods peuvent être créés ou supprimés simultanément. Kubernetes n’attend pas que chaque Pod soit Ready avant de passer au suivant.

spec:
podManagementPolicy: Parallel

Cas d’usage : applications tolérantes au démarrage simultané, où la vitesse de scaling est prioritaire sur l’ordre.

Fenêtre de terminal
kubectl scale sts web --replicas=5

Avec OrderedReady, les nouveaux Pods sont créés dans l’ordre : web-3, puis web-4.

Fenêtre de terminal
kubectl scale sts web --replicas=2

Les Pods sont supprimés en ordre inverse : web-4, web-3, web-2.

Pour supprimer le StatefulSet sans toucher aux Pods :

Fenêtre de terminal
kubectl delete sts web --cascade=orphan

Les Pods continuent de tourner, mais ne sont plus gérés par un contrôleur. Utile pour recréer un StatefulSet avec une configuration différente.

Fenêtre de terminal
kubectl delete sts web

Cela supprime le StatefulSet et ses Pods, mais pas les PVC.

Fenêtre de terminal
kubectl delete sts web
kubectl delete pvc -l app=nginx

Politique de rétention des PVC (Kubernetes 1.27+)

Section intitulée « Politique de rétention des PVC (Kubernetes 1.27+) »

Depuis Kubernetes 1.27, vous pouvez configurer le comportement des PVC lors de la suppression ou du scaling avec persistentVolumeClaimRetentionPolicy :

spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain # Garde les PVC quand le StatefulSet est supprimé
whenScaled: Delete # Supprime les PVC quand le Pod est supprimé par scaling
ValeurComportement
RetainLes PVC sont conservés (comportement par défaut actuel)
DeleteLes PVC sont supprimés avec le Pod/StatefulSet
SymptômeCause probableSolution
Pod PendingPas de PV disponible ou StorageClass manquantekubectl describe pod + vérifier StorageClass
Pod ne démarre pasPod précédent pas ReadyVérifier l’état du Pod d’ordinal inférieur
PVC PendingProvisioner défaillant ou quota atteintkubectl describe pvc
DNS non résoluHeadless Service manquant ou mal configuréVérifier clusterIP: None
Mise à jour bloquéePod en erreurkubectl describe pod + logs
Fenêtre de terminal
# Voir les événements du StatefulSet
kubectl describe sts web
# Vérifier un Pod spécifique
kubectl describe pod web-0
kubectl logs web-0
# Vérifier les PVC
kubectl describe pvc www-web-0
# État du rollout
kubectl rollout status sts/web --timeout=60s

Comparatif : Deployment vs StatefulSet vs DaemonSet

Section intitulée « Comparatif : Deployment vs StatefulSet vs DaemonSet »

Choisir la bonne ressource est essentiel pour la CKAD.

CritèreDeploymentStatefulSetDaemonSet
Identité des PodsAnonymeStable (app-0, app-1)Anonyme
NommageHash aléatoireOrdinal incrémentalHash aléatoire
StockagePVC partagé ou sans étatPVC dédié par PodGénéralement hostPath
Ordre de déploiementNon garantiOrdonné (par défaut)Non garanti
DNS stableNonOui (headless Service)Non
ScalingHorizontal libreOrdonnéSuit les nœuds
Cas d’usageAPIs, web statelessBases de données, clustersAgents système
Votre application a-t-elle besoin de :
├── Tourner sur CHAQUE nœud éligible ?
│ └── → DaemonSet
├── Identité stable + stockage persistant par instance ?
│ └── → StatefulSet
└── Ni l'un ni l'autre ?
└── → Deployment

Voici un exemple plus complet avec anti-affinité pour répartir les Pods sur différents nœuds :

statefulset-distributed.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: distributed-app
spec:
serviceName: distributed-app
replicas: 3
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
selector:
matchLabels:
app: distributed-app
template:
metadata:
labels:
app: distributed-app
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: distributed-app
topologyKey: kubernetes.io/hostname
terminationGracePeriodSeconds: 30
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "echo 'Pod $(hostname) started'; sleep infinity"]
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: data
mountPath: /data
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
exec:
command: ["cat", "/tmp/ready"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi

Points clés :

  • podAntiAffinity : empêche deux Pods d’être sur le même nœud
  • terminationGracePeriodSeconds: 30 : laisse le temps à l’application de se terminer proprement
  • livenessProbe et readinessProbe : essentiels pour les rolling updates ordonnés
  1. Un StatefulSet fournit une identité stable (app-0, app-1) et un stockage persistant dédié par Pod
  2. Il nécessite un headless Service (clusterIP: None) pour le DNS stable
  3. La stratégie de mise à jour par défaut est RollingUpdate, pas OnDelete
  4. volumeClaimTemplates crée automatiquement un PVC par Pod
  5. Les mises à jour se font en ordre inverse (du plus grand ordinal vers le plus petit)
  6. podManagementPolicy: Parallel accélère le scaling mais pas les updates
  7. Les PVC ne sont pas supprimés automatiquement lors d’un scale down ou d’une suppression du StatefulSet (sauf avec persistentVolumeClaimRetentionPolicy)
  8. Le DNS d’un Pod est <pod>.<service>.<namespace>.svc.cluster.local

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
90% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn