infra / kubernetes
StatefulSets
Explication
Ce que vous allez apprendre
- Comprendre la différence entre des Pods interchangeables (Deployment) et une identité stable (StatefulSet)
- Identifier les trois garanties qu'apporte un StatefulSet (noms, stockage, ordre)
- Comprendre pourquoi un Service headless est indispensable au fonctionnement d'un StatefulSet
- Reconnaître les cas d'usage réels d'un StatefulSet (bases de données, Kafka, etcd)
- Savoir quand un Deployment classique reste préférable à un StatefulSet
Dans quel contexte ?
Une équipe déploie un cluster PostgreSQL avec un simple Deployment à 3 replicas, comme elle le ferait pour une API web classique. Résultat : à chaque redémarrage, les Pods reçoivent de nouveaux noms aléatoires et perdent leur volume de stockage précédent, ce qui casse la réplication entre les instances de la base — chaque nouvelle instance repart de zéro sans données. Le StatefulSet existe précisément pour ce genre de charge : il garantit des noms stables (postgres-0, postgres-1, postgres-2), un volume dédié qui suit chaque instance, et un ordre de création prévisible.
Ce que les Pods interchangeables ne permettent pas
D'abord, tout le cours jusqu'ici a valorisé des Pods interchangeables et sans identité propre : peu importe lequel répond, un Deployment peut les remplacer librement.
Un besoin exactement inverse
Mais certaines applications, en particulier les bases de données distribuées ou les systèmes de clustering, ont besoin exactement du contraire : une identité stable. Chaque instance doit garder le même nom, le même stockage, et parfois connaître son rang dans le groupe.
L'objet conçu pour ce besoin
C'est le rôle du StatefulSet. Il apporte trois garanties qu'un Deployment classique ne fournit pas.
| Garantie du StatefulSet | Ce que ça évite |
|---|---|
Noms de Pods stables (postgres-0, postgres-1...) | Des noms aléatoires à chaque redémarrage |
| Stockage dédié et persistant par instance | La perte de données lors d'une recréation |
| Ordre garanti de création/suppression | Une instance secondaire créée avant la primaire |
Première garantie : des noms prévisibles
D'abord, des noms de Pods prévisibles et stables, comme postgres-0, postgres-1, postgres-2, qui restent les mêmes même après un redémarrage, contrairement aux noms générés aléatoirement d'un Deployment.
Deuxième garantie : un stockage dédié
Ensuite, un stockage dédié et persistant par instance : chaque replica garde son propre volume, jamais partagé, et le retrouve même après recréation.
Troisième garantie : un ordre garanti
Enfin, un ordre garanti de création et de suppression, essentiel pour des systèmes où l'instance numéro 0 doit exister avant les suivantes, un cas fréquent dans les bases distribuées.
Piège fréquent
Utiliser un StatefulSet "par défaut" pour une application web classique sans état ajoute de la complexité pour rien : mises à jour plus lentes, gestion plus délicate, sans aucun bénéfice réel. Réserve le StatefulSet aux charges qui ont vraiment besoin d'une identité stable.
Une brique réseau facile à oublier
Pour que chaque Pod ait sa propre adresse DNS individuelle, et non une adresse partagée par le groupe, un StatefulSet a besoin d'un Service particulier dit "headless", sans IP virtuelle propre.
Ce qui casse sans cette brique
Sans ce Service headless, l'identité réseau individuelle promise par le StatefulSet ne fonctionne tout simplement pas.
Bonne pratique
Avant de choisir un StatefulSet, pose-toi la question inverse : "mon application a-t-elle vraiment besoin qu'une instance précise garde son identité et son stockage ?" Si la réponse est non, un Deployment classique reste plus simple à opérer et suffit largement.
Un outil à réserver aux vrais besoins d'état
Le StatefulSet est plus complexe à opérer qu'un Deployment, avec des mises à jour plus lentes et une gestion plus délicate. Réserve-le aux charges réellement stateful, comme les bases de données, Kafka ou etcd ; pour une application web classique, un Deployment simple reste le bon choix.
La leçon suivante quitte les charges permanentes pour un besoin différent : des tâches qui doivent s'exécuter une fois puis s'arrêter, avec les Jobs et CronJobs.
Commandes & code
StatefulSets
Pour les workloads avec état qui ont besoin d'une identité stable (nom, stockage, ordre) : bases de données, clusters distribués.
# headless service - requis par un StatefulSet pour l'identité réseau stable de chaque Pod
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
spec:
clusterIP: None # "headless" : pas de load balancing, DNS pointe direct vers chaque Pod
selector:
app: postgres
ports:
- port: 5432apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres-headless
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# Chaque replica obtient SON PROPRE PVC, créé à partir de ce template
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 20Gikubectl apply -f postgres-statefulset.yaml
kubectl get pods -l app=postgres
# Pods nommés de façon PRÉVISIBLE et STABLE : postgres-0, postgres-1, postgres-2
# (contrairement à un Deployment où les noms sont aléatoires)
# DNS individuel et stable par Pod (grâce au service headless)
# postgres-0.postgres-headless.default.svc.cluster.local
kubectl get pvc
# data-postgres-0, data-postgres-1, data-postgres-2 : un PVC dédié PAR Pod, jamais partagé# Ordre garanti : création/suppression séquentielle (postgres-0 avant postgres-1, etc.)
kubectl delete pod postgres-1
# Kubernetes recrée "postgres-1" avec la MÊME identité et le MÊME PVC (pas un nouveau volume vide)Résumé
- StatefulSet = identité stable (nom, DNS, PVC dédié) + ordre de création/suppression garanti.
- Nécessite un Service
headless(clusterIP: None) pour le DNS individuel par Pod. volumeClaimTemplatescrée un PVC unique et persistant par replica, jamais partagé.- À réserver aux vraies charges avec état (bases, Kafka, etcd) ; sinon un Deployment suffit.
Exercices pratiques
Mission : réparer un cluster Postgres qui a perdu son DNS interne
Objectif : Diagnostiquer et corriger un StatefulSet Postgres dont le Service headless manque, puis vérifier que l'identité et le stockage de chaque replica survivent à une recréation.
Contexte
Un ancien Deployment Postgres a été converti en StatefulSet postgres à 3 replicas, mais le Service postgres-headless référencé dans spec.serviceName n'a jamais été créé. Résultat : postgres-1 ne parvient pas à joindre postgres-0 pour la réplication, alors que les noms de Pods (postgres-0, postgres-1, postgres-2) semblent pourtant corrects dans kubectl get pods.