Introduction
Exécuter des applications avec état répliquées sur Kubernetes est l’un des défis opérationnels les plus difficiles en orchestration de conteneurs. Contrairement aux charges de travail sans état, les applications avec état telles que les bases de données, les files de messages et les caches distribués nécessitent des identités réseau stables, un stockage durable et une coordination minutieuse entre les réplicas. Une seule erreur de configuration peut entraîner des scénarios de split-brain, une perte de données silencieuse ou des défaillances en cascade qui mettent hors service tout un service.
Ce guide couvre les erreurs de configuration les plus courantes dans les StatefulSets Kubernetes, comment valider les changements en toute sécurité et que faire lorsque les choses tournent mal. Vous apprendrez à inspecter votre environnement actuel, à appliquer des mises à jour progressives avec des partitions canaries, à vérifier la santé de la réplication et à récupérer des modes de défaillance courants. À la fin, vous disposerez d’un processus reproductible pour déployer et exploiter des applications avec état répliquées en toute confiance.
Inventaire de version et d’environnement
Avant de modifier toute configuration, documentez votre environnement actuel. Connaître votre version de Kubernetes, vos classes de stockage et la topologie de l’application évite les incompatibilités qui provoquent des défaillances cachées plus tard. Exécutez les commandes suivantes et enregistrez la sortie dans un runbook ou un document versionné :
# Vérifier les versions du client et du serveur Kubernetes
kubectl version --short
# Vérifier les classes de stockage disponibles
kubectl get storageclass
# Lister les StatefulSets dans l’espace de noms actuel
kubectl get statefulsets
Exemple de sortie :
Client Version: v1.28.0
Server Version: v1.28.0
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
standard (default) kubernetes.io/gce-pd Delete Immediate false 1d
NAME READY AGE
my-statefulset 3/3 2h
Enregistrez des détails tels que le nom du service du StatefulSet, la politique de gestion des pods et la stratégie de mise à jour. Ces champs sont définis dans la spécification du StatefulSet et affectent directement les mises à jour progressives, l’ordre de remplacement des pods et l’identité réseau. Inspectez-les avec :
kubectl get statefulset my-statefulset -o yaml | grep -A5 -E 'serviceName|podManagementPolicy|updateStrategy'
Exemple de sortie :
serviceName: my-service
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
Les prérequis pour des changements sûrs incluent :
- Un espace de noms de test dédié avec la même classe de stockage et les mêmes politiques réseau.
- Des procédures de sauvegarde des volumes persistants, testées régulièrement.
- L’accès aux journaux d’application et aux métriques (par exemple, Prometheus, Loki).
- Un plan de retour en arrière : stocker les manifestes précédents dans Git, ou utiliser Helm avec l’historique des versions.
Chemin de configuration sûr
Les erreurs de configuration proviennent souvent d’une mauvaise compréhension de la façon dont les StatefulSets gèrent les mises à jour et l’identité. Pour les applications répliquées, les erreurs courantes incluent :
- Utiliser le mauvais
serviceName, cassant les noms DNS stables commemyapp-0.my-service. - Mal configurer
podManagementPolicy, provoquant des opérations parallèles inattendues lorsque le démarrage ordonné est requis. - Utiliser
RollingUpdateavec des valeurs departitionincorrectes, mettant à jour trop de réplicas à la fois et risquant une perte de quorum. - Ignorer
volumeClaimTemplates, conduisant à un stockage partagé ou à l’absence de persistance pour les données avec état. - Fixer des limites de ressources trop basses, provoquant des
OOMKilledau démarrage ou en fonctionnement normal.
Pour éviter ces pièges, adoptez un chemin d’implémentation limité. Au lieu de mettre à jour tous les réplicas simultanément, utilisez une mise à jour progressive avec une partition pour créer un canari. Par exemple, avec trois réplicas (myapp-0, myapp-1, myapp-2), définissez partition: 2. Cela signifie que seuls les pods avec un ordinal supérieur ou égal à 2 (c’est-à-dire myapp-2) seront mis à jour. Les deux autres pods restent sur la version précédente, ce qui vous permet de valider le changement sur un seul réplica avant de le déployer davantage.
Voici un manifeste StatefulSet complet avec des valeurs par défaut sûres :
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-statefulset
spec:
serviceName: "my-service"
replicas: 3
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Mettre à jour uniquement le pod avec ordinal >= 2 (myapp-2)
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: standard
resources:
requests:
storage: 1Gi
template:
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
Appliquez les changements progressivement et vérifiez chaque étape. Utilisez kubectl apply avec le manifeste modifié :
kubectl apply -f updated-statefulset.yaml
Après application, surveillez l’état du déploiement :
kubectl rollout status statefulset/my-statefulset
Sortie attendue lors d’une mise à jour canari :
Waiting for 1 pods to be ready...
Waiting for 1 pod to be ready...
statefulset rolling update complete 1 pods at revision my-statefulset-7d9f9d6f7
Si le déploiement stagne, inspectez les événements et les journaux du pod avant de continuer. Ne forcez pas le déploiement ; recherchez d’abord la cause.
Vérification et diagnostics
Après avoir appliqué les changements de configuration, vérifiez la santé de chaque réplica. Pour les applications avec état répliquées, la cohérence et l’intégrité des données sont critiques. Utilisez les commandes et vérifications suivantes.
Vérifier l’état des pods et leur disponibilité :
kubectl get pods -l app=myapp -o wide
Sortie attendue :
NAME READY STATUS RESTARTS AGE IP NODE
myapp-0 1/1 Running 0 10m 10.0.0.1 node1
myapp-1 1/1 Running 0 10m 10.0.0.2 node2
myapp-2 1/1 Running 0 10m 10.0.0.3 node3
Vérifier les PVC liés à chaque pod :
kubectl get pvc -l app=myapp
Sortie attendue :
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-myapp-0 Bound pvc-0d1f7c42-1a5a-4f4d-9a5b-0f0a5e5f0a5a 1Gi RWO standard 10m
data-myapp-1 Bound pvc-5d7e3e1f-8b3c-4c1d-8d0a-2b1e2f1d2e1f 1Gi RWO standard 10m
data-myapp-2 Bound pvc-9f8e7c6d-2c3b-4d5e-6f7a-3c4d5e6f7a8b 1Gi RWO standard 10m
Vérifier les journaux pour la santé de la réplication :
kubectl logs myapp-0
Exemple de sortie pour un réplica de base de données :
2024-01-01T12:00:00Z [Replication] INFO: Successfully connected to primary
2024-01-01T12:00:01Z [Replication] INFO: Replication lag: 0 ms
Contrôles de diagnostic à effectuer :
- Assurez-vous que chaque pod possède un volume persistant unique. L’utilisation de
ReadWriteOnceempêche plusieurs pods de monter le même volume. - Vérifiez l’état de la réplication via les métriques ou les journaux de l’application. Pour les bases de données, vérifiez
SHOW SLAVE STATUSou équivalent. - Exécutez un test d’écriture sur un réplica et une lecture sur un autre, si l’application le prend en charge. Par exemple, insérez une ligne dans
myapp-0et interrogez-la depuismyapp-1pour confirmer la réplication. - Utilisez
kubectl execpour exécuter des commandes de santé spécifiques à l’application. Pour un StatefulSet PostgreSQL, vous pouvez exécuter :
kubectl exec myapp-0 -- psql -c "SELECT 1"
Si une vérification échoue, suspendez le déploiement et enquêtez.
Modes de défaillance et récupération
Malgré les précautions, des défaillances surviennent. Les modes de défaillance courants incluent :
- Pod bloqué en
Pendingen raison de ressources insuffisantes, de problèmes de classe de stockage ou de contraintes d’affinité de nœud. - Boucle de crash du pod causée par une mauvaise configuration, des dépendances manquantes ou une version d’image incompatible.
- Incohérence des données après un arrêt non propre, comme une défaillance de nœud sans fsync approprié.
- Split-brain lorsque des partitions réseau isolent les réplicas et que les deux côtés tentent de devenir primaires.
Étapes de récupération :
1. Diagnostiquer la défaillance. Si un déploiement échoue, vérifiez les événements et les détails du pod :
kubectl describe pod myapp-1
Recherchez des messages comme Failed to attach volume, Insufficient cpu ou CrashLoopBackOff. Vérifiez également les journaux :
kubectl logs myapp-1 --previous
2. Revenir à la version précédente. Si vous avez le manifeste précédent dans Git ou avez utilisé Helm, exécutez :
kubectl rollout undo statefulset/my-statefulset
Cela revient à la révision précédente. Vérifiez que le retour se termine :
kubectl rollout status statefulset/my-statefulset
Si vous utilisez Helm, vous pouvez revenir à une version antérieure :
helm rollback my-release 2
3. Restaurer à partir d’une sauvegarde pour les problèmes de données. Assurez-vous que les sauvegardes sont testées régulièrement. Pour les volumes cloud, utilisez des instantanés ; pour les bases de données, utilisez des sauvegardes logiques (par exemple, pg_dump).
4. Remplacer un pod défaillant si nécessaire. Si un pod est bloqué ou corrompu, vous pouvez le supprimer ; le contrôleur StatefulSet le recréera avec la même identité et le même PVC. Utilisez ceci avec prudence :
kubectl delete pod myapp-1
Le pod sera recréé, mais son PVC reste. Remarque : cela ne revient pas à la configuration précédente ; cela ne fait que replanifier le pod.
Documentez toujours l’incident et les étapes de récupération pour référence future. Testez régulièrement les procédures de retour en arrière dans un environnement hors production pour vous assurer qu’elles fonctionnent en cas de besoin.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle avant et après avoir apporté des modifications de configuration aux applications avec état répliquées. Elle garantit la cohérence et réduit les erreurs.
| Étape | Description | Commande / Action |
|---|---|---|
| 1 | Enregistrer les versions de référence | kubectl version --short |
| 2 | Lister les détails du StatefulSet | kubectl get statefulset -o yaml |
| 3 | Sauvegarder les volumes persistants | Utiliser l’instantané du fournisseur de stockage ou un outil (par exemple, Velero) |
| 4 | Appliquer le changement avec partition pour le canari | kubectl apply -f updated-statefulset.yaml avec partition: 2 |
| 5 | Surveiller l’état du déploiement | kubectl rollout status statefulset/my-statefulset |
| 6 | Vérifier la disponibilité des pods | kubectl get pods -l app=myapp |
| 7 | Vérifier les journaux d’application pour la santé de la réplication | kubectl logs myapp-0 |
| 8 | Exécuter des tests spécifiques à l’application | Pour une base de données, exécuter un test de requête (par exemple, écrire sur le primaire, lire depuis le réplica) |
| 9 | En cas d’échec, revenir en arrière | kubectl rollout undo statefulset/my-statefulset |
| 10 | Documenter le résultat et mettre à jour le runbook | Mettre à jour le wiki interne ou le dépôt Git |
Conclusion
Exécuter des applications avec état répliquées sur Kubernetes exige une configuration minutieuse et des opérations disciplinées. En comprenant les erreurs courantes, en utilisant des mises à jour limitées avec des partitions, en vérifiant avec des diagnostics et en ayant un plan de retour en arrière, vous pouvez maintenir une haute disponibilité et l’intégrité des données. Commencez par un pilote étroit, mesurez les résultats et itérez. Les commandes et la liste de contrôle fournies vous donnent une base solide pour exploiter des charges de travail avec état de manière fiable. N’oubliez pas que les applications avec état nécessitent des soins supplémentaires : chaque changement doit être traité comme potentiellement perturbateur et chaque défaillance doit être analysée pour éviter qu’elle ne se reproduise.