Aller au contenu

Maîtrisez les StatefulSets Kubernetes

Mise à jour :

logo kubernetes

Lorsque l’on déploie une application avec état sur une cluster Kubernetes comme une base de données, un système de stockage distribué ou un cluster de données réparties, plusieurs défis apparaissent. Comment garantir que chaque instance conserve son identité unique ? Comment s’assurer que les données restent associées au bon Pod, même après un redémarrage ?

Avec un simple ReplicaSet, les Pods sont interchangeables : Kubernetes les recrée dynamiquement sans distinction. Mais dans le cas d’un système distribué, chaque nœud a un rôle bien précis et ne peut pas être recréé aléatoirement.

Alors, comment Kubernetes peut-il gérer ce besoin de persistance et d’identité stable pour chaque instance ? C’est précisément ce que nous allons explorer.

StatefulSet : La solution Kubernetes pour les applications avec état

Pour répondre aux exigences des applications nécessitant une persistance des données et une identité unique par instance, Kubernetes propose une ressource spécifique : le StatefulSet. Contrairement aux ReplicaSets, qui gèrent des Pods interchangeables, les StatefulSets sont conçus pour les déploiements ou chaque Pod doit conserver son état et son identité sur le long terme.

Une identité unique et persistante pour chaque Pod

Un StatefulSet assure que chaque Pod qu’il gère possède un nom stable et incrémental. Contrairement aux ReplicaSets, où les Pods sont nommés de façon aléatoire, les Pods d’un StatefulSet suivent une nomenclature prévisible basée sur leur index (nom-du-statefulset-0, nom-du-statefulset-1, etc.).

Ce comportement garantit que chaque instance d’application garde une identité propre, essentielle pour les bases de données distribuées, où chaque nœud a un rôle bien défini au sein du cluster.

De plus, Kubernetes assure un ordre strict de démarrage et d’arrêt des Pods :

  1. Un Pod ne sera pas lancé tant que le précédent n’est pas totalement opérationnel.
  2. Lorsqu’un Pod est supprimé, les autres ne sont pas affectés, et un nouveau Pod avec le même nom sera recréé en cas de besoin.

Ce comportement est particulièrement important pour des systèmes tels que Apache Zookeeper, Kafka, Etcd ou encore MySQL en cluster, où l’ordre d’initialisation des nœuds est primordial.

Un stockage persistant propre à chaque Pod

L’un des défis majeurs des applications avec état est la gestion du stockage. Contrairement aux ReplicaSets, où les volumes sont partagés entre tous les Pods, les StatefulSets attribuent un volume persistant distinct à chaque instance de Pod.

Chaque Pod possède son propre PersistentVolumeClaim (PVC), qui ne change pas même si le Pod est recréé ou déplacé sur un autre nœud du cluster. Cela permet de garantir que les données associées à un Pod restent toujours accessibles, indépendamment des cycles de vie du Pod lui-même.

Ce mécanisme est essentiel pour les bases de données et systèmes distribués, qui exigent une cohérence des données et une persistance fiable. Par exemple, dans un cluster PostgreSQL en haute disponibilité, chaque nœud détient une copie des données et doit conserver son propre état.

Un accès réseau stable et individualisé

Les StatefulSets s’appuient sur un Service Headless pour offrir une résolution DNS spécifique à chaque Pod. Contrairement à un Service classique qui expose l’ensemble des Pods derrière une seule adresse IP, un Service Headless assigne un nom DNS unique à chaque instance (pod-0, pod-1, pod-2), ce qui permet aux applications distribuées de se connecter directement à une instance précise.

Ce comportement est particulièrement utile dans des systèmes où chaque nœud joue un rôle spécifique, comme dans un cluster Elasticsearch ou Cassandra, où chaque Pod stocke un fragment spécifique des données globales.

Les limites du StatefulSet

Si les StatefulSets sont essentiels pour les applications avec état, ils ne gèrent pas automatiquement les mises à jour des Pods. Contrairement aux Deployments, qui permettent des mises à jour progressives via le mécanisme de rolling update, un StatefulSet ne remplacera pas directement un Pod avec une nouvelle version.

Pour mettre à jour une application utilisant un StatefulSet, il est souvent nécessaire de :

  • Mettre à jour chaque instance manuellement en respectant l’ordre du cluster.
  • Effectuer des migrations de données avant d’appliquer un changement majeur.
  • Superviser les dépendances pour éviter toute interruption de service.

Création d’un StatefulSet from scratch : Déploiement de Consul

Présentation de l’architecture

Dans cet exemple, nous allons déployer Consul sous forme d’un StatefulSet sur Kubernetes. Consul est un système de service discovery, de configuration et de gestion de réseau souvent utilisé pour les architectures microservices.

L’objectif ici est de créer un cluster hautement disponible de 3 nœuds Consul, chacun ayant :

  • Une identité unique (consul-0, consul-1, consul-2).
  • Un stockage persistant dédié pour conserver les données.
  • Un mécanisme de sécurisation des communications avec des clés d’encryptions et du TLS.
  • Une gestion stricte de l’affinité des Pods pour répartir les instances sur différents nœuds.

Nous allons détailler chaque section du manifeste YAML utilisé pour cette configuration.

1. Définition du StatefulSet :

Le StatefulSet est défini sous l’API apps/v1 et nommé consul. Kubernetes va gérer 3 réplicas, chacun possédant un volume dédié et une identité persistante.

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: consul
spec:
replicas: 3
serviceName: consul
selector:
matchLabels:
app: consul
component: server
  • replicas: 3 → Kubernetes crée 3 instances de Consul, qui seront consul-0, consul-1 et consul-2.
  • serviceName: consul → Permet de donner une résolution DNS unique à chaque Pod (consul-0.consul, consul-1.consul, etc.).
  • selector.matchLabels → Garantit que seuls les Pods avec ces labels seront gérés par ce StatefulSet.

2. Gestion de l’affinité des Pods :

Le cluster Consul doit être réparti sur plusieurs nœuds Kubernetes pour éviter qu’un seul nœud héberge toutes les instances. C’est ici que l’affinité des Pods intervient :

affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- consul
topologyKey: kubernetes.io/hostname
  • podAntiAffinity → Empêche plusieurs instances de Consul de s’exécuter sur le même nœud.
  • topologyKey: kubernetes.io/hostname → Kubernetes tente de distribuer chaque Pod sur un nœud différent, améliorant ainsi la résilience du cluster.

3. Gestion du cycle de vie et des connexions :

terminationGracePeriodSeconds: 10
containers:
- name: consul
image: "consul:1.4.0-rc1"
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- consul leave
  • terminationGracePeriodSeconds: 10 → Donne 10 secondes aux Pods avant leur suppression, évitant des coupures brutales.
  • preStop → Avant d’être supprimé, chaque Pod exécute la commande consul leave, ce qui permet de quitter proprement le cluster et de prévenir les autres nœuds.

4. Configuration réseau et ports exposés :

Consul expose plusieurs ports pour ses différentes fonctionnalités :

ports:
- containerPort: 8500
name: ui-port
- containerPort: 8301
name: serflan
- containerPort: 8302
name: serfwan
- containerPort: 8600
name: consuldns
- containerPort: 8300
name: server
  • 8500 → Interface utilisateur Web de Consul.
  • 8300 → Communication entre les serveurs du cluster.
  • 8301 & 8302 → Protocoles de communication Serf LAN/WAN.
  • 8600 → Service DNS interne de Consul.

Ces ports permettent aux nœuds de Consul de se découvrir et de communiquer entre eux, garantissant un fonctionnement fluide du cluster.

5. Gestion des volumes persistants :

Chaque instance de Consul a besoin d’un stockage dédié, notamment pour les données du cluster et l’état des services.

volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
  • volumeClaimTemplates → Définit un volume distinct pour chaque Pod (data-consul-0, data-consul-1, etc.).
  • ReadWriteOnce → Chaque volume est attaché uniquement à un seul nœud.
  • storage: 10Gi → Réserve 10 Go de stockage par instance de Consul.

Chaque Pod conservera son volume même après un redémarrage ou un déplacement, garantissant ainsi la persistance des données.

6. Sécurisation avec TLS et chiffrement des communications :

Consul utilise un chiffrement des échanges entre les nœuds via des clés secrètes stockées dans Kubernetes.

env:
- name: GOSSIP_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: consul
key: gossip-encryption-key
  • GOSSIP_ENCRYPTION_KEY → Récupère une clé d’encryption depuis un Secret Kubernetes.
  • tls → Un volume Secret est monté pour stocker les certificats TLS et sécuriser les communications.
volumes:
- name: tls
secret:
secretName: consul

7. Gestion du lancement de Consul :

Enfin, voici les arguments passés au conteneur pour initialiser correctement le cluster Consul :

args:
- "agent"
- "-advertise=$(POD_IP)"
- "-bootstrap-expect=3"
- "-config-file=/etc/consul/config/server.json"
- "-encrypt=$(GOSSIP_ENCRYPTION_KEY)"
  • -advertise=$(POD_IP) → Chaque instance annonce son adresse IP interne au cluster.
  • -bootstrap-expect=3 → Indique que le cluster attend 3 nœuds minimum avant de fonctionner pleinement.
  • -encrypt=$(GOSSIP_ENCRYPTION_KEY) → Active le chiffrement des communications entre nœuds.
  • -config-file=/etc/consul/config/server.json → Charge une configuration personnalisée via un ConfigMap.

Résumé

Avec ce StatefulSet, nous avons déployé un cluster Consul sécurisé, persistant et hautement disponible sur Kubernetes.

Les principaux avantages de cette approche sont :

  • Chaque nœud a une identité stable (consul-0, consul-1, etc.).
  • Les données sont stockées sur des volumes persistants, indépendamment du cycle de vie des Pods.
  • L’anti-affinité garantit une répartition optimale sur plusieurs nœuds.
  • Le chiffrement sécurise toutes les communications entre les instances.

Cette configuration est idéale pour gérer la découverte de services, le stockage des configurations et le routage des communications au sein d’un cluster Kubernetes.

Déploiement, gestion et suppression d’un StatefulSet

Une fois le StatefulSet défini, il faut savoir le déployer, le gérer et éventuellement le supprimer proprement. Contrairement aux ReplicaSets, les StatefulSets impliquent des spécificités importantes à prendre en compte, notamment en ce qui concerne l’ordre de démarrage des Pods et la persistance des volumes.

Déploiement d’un StatefulSet

Le déploiement d’un StatefulSet suit plusieurs étapes :

  1. Appliquer le manifeste YAML : Une fois le fichier YAML du StatefulSet rédigé, utilisez la commande suivante pour le déployer dans le cluster Kubernetes :

    Terminal window
    kubectl apply -f statefulset-consul.yaml
  2. Vérifier la création des Pods et des volumes : Kubernetes va créer les Pods un par un, dans un ordre séquentiel (pod-0pod-1pod-2), ce qui peut prendre plus de temps qu’un ReplicaSet.

    Vous pouvez surveiller leur état avec :

    Terminal window
    kubectl get pods -l app=consul

    Chaque Pod aura un nom unique et stable, comme consul-0, consul-1, consul-2.

  3. Vérifier la création des volumes persistants : Contrairement aux ReplicaSets, chaque Pod du StatefulSet aura son propre Persistent Volume Claim (PVC). Listez les volumes associés :

    Terminal window
    kubectl get pvc

    Vous devriez voir des volumes avec des noms spécifiques à chaque Pod, comme :

    Terminal window
    NAME STATUS VOLUME CAPACITY ACCESS MODES
    data-consul-0 Bound pvc-xyz01 10Gi RWO
    data-consul-1 Bound pvc-xyz02 10Gi RWO
    data-consul-2 Bound pvc-xyz03 10Gi RWO
  4. Vérifier le bon fonctionnement des Pods : Pour voir les logs d’un Pod particulier, utilisez :

    Terminal window
    kubectl logs consul-0

    Si un Pod rencontre des problèmes (CrashLoopBackOff, Pending), utilisez kubectl describe pour afficher les détails :

    Terminal window
    kubectl describe pod consul-0

Gestion et mise à jour d’un StatefulSet

Une fois le StatefulSet déployé, vous pouvez avoir besoin de modifier le nombre de réplicas, mettre à jour les configurations ou remplacer des Pods.

Mise à jour d’un StatefulSet

Contrairement aux Deployments, un StatefulSet ne met pas à jour automatiquement ses Pods lorsqu’une modification du template est appliquée.

Si vous devez modifier l’image d’un conteneur ou une variable d’environnement, vous devez redémarrer les Pods un par un en attendant que le pod soit actif, pour éviter de perturber l’état du cluster :

Terminal window
kubectl delete pod consul-0
kubectl delete pod consul-1
kubectl delete pod consul-2

À chaque suppression, Kubernetes recrée le Pod avec les nouvelles configurations, mais en conservant le même volume de stockage.

Accéder aux Pods du StatefulSet

Chaque Pod a une adresse DNS unique grâce au Service Headless (consul.default.svc.cluster.local). Vous pouvez tester l’accès depuis un autre Pod avec :

Terminal window
kubectl exec -it some-pod -- nslookup consul-0.consul.default.svc.cluster.local

Pour accéder directement à l’interface Web de Consul :

Terminal window
kubectl port-forward pod/consul-0 8500:8500

Puis ouvrez http://localhost:8500 dans un navigateur.

Suppression propre d’un StatefulSet

Lorsque vous supprimez un StatefulSet, il est important de bien gérer les volumes persistants, car Kubernetes ne supprime pas automatiquement les PVC.

Suppression du StatefulSet sans supprimer les volumes

Si vous voulez supprimer uniquement les Pods mais conserver les données, utilisez :

Terminal window
kubectl delete statefulset consul --cascade=orphan

Cela supprimera le StatefulSet, mais les Pods et les volumes persisteront, vous permettant de recréer le StatefulSet sans perte de données.

Vérifiez les volumes toujours présents :

Terminal window
kubectl get pvc

Suppression complète du StatefulSet et des volumes

Si vous voulez supprimer totalement le StatefulSet et ses données, utilisez :

Terminal window
kubectl delete statefulset consul
kubectl delete pvc -l app=consul

Attention : Cette opération est irréversible et entraîne la perte définitive des données stockées.

Contrôle de connaissances

Pourquoi ce contrôle ?

Cet contrôle va vous permettre de valider vos connaissances sur le sujet abordé dans le guide. Il comporte des QCM, des questions vrai/faux et des réponses ouvertes à un mot.

🕒 Le chronomètre commence dès que vous cliquez sur Démarrer le test. Vous devrez terminer l’examen avant la fin du temps imparti.

🎯 Pour réussir, vous devez obtenir au moins 90% de bonnes réponses.

💡 Je ne fournis pas directement les réponses aux questions. Cependant, si certaines sont complexes, des pistes d’explication pourront être proposées dans le guide ou après l’examen.

Bonne chance ! 🚀

Conclusion

Le StatefulSet est une ressource puissante de Kubernetes, conçue pour répondre aux besoins spécifiques des applications avec état. Il permet de garantir une identité stable des Pods, un stockage persistant dédié et un contrôle strict de l’ordre de déploiement et de suppression. Ces caractéristiques en font un choix incontournable pour les bases de données, les clusters distribués et les applications nécessitant une haute disponibilité.

Cependant, maîtriser un StatefulSet ne s’improvise pas. Contrairement aux Deployments ou aux ReplicaSets, il impose des contraintes spécifiques qui exigent une compréhension approfondie de Kubernetes. La gestion des volumes persistants, la mise à jour des Pods, l’anti-affinité entre les nœuds et les politiques de mise à l’échelle sont autant d’aspects qu’il faut anticiper sous peine de compromettre la stabilité et la cohérence des données.

Utiliser un StatefulSet demande donc une expertise en administration Kubernetes, une connaissance des bonnes pratiques en matière de stockage, de mise en réseau et de haute disponibilité. Avant de l’adopter en production, il est essentiel de bien tester son fonctionnement, d’établir des plans de sauvegarde et de reprise, et de comprendre ses limites.

Si votre application nécessite un StatefulSet, assurez-vous d’avoir les compétences et les outils pour le gérer correctement. Dans le cas contraire, il vaut mieux se tourner vers des solutions managées ou utiliser un Deployment avec un stockage externe, selon les besoins.

En maîtrisant le StatefulSet, vous aurez entre les mains un outil puissant pour déployer et gérer des applications critiques avec résilience et fiabilité sur Kubernetes.