Introduction
Exécuter des applications avec état sur Kubernetes introduit des défis que les charges de travail sans état ne rencontrent pas. Les identités réseau stables, le stockage persistant et la mise à l'échelle ordonnée exigent une gestion prudente lors du déploiement. Ce guide montre aux praticiens comment construire une automatisation CI/CD pour les StatefulSets Kubernetes à l'aide d'exemples concrets et testés. Vous apprendrez à observer votre cluster avant de le modifier, à concevoir des pipelines qui protègent les données persistantes, à vérifier les mises en production et à récupérer après un incident sans perte de données ni interruption de service.
Nous mettons l'accent sur des commandes concrètes, des extraits de configuration et les résultats attendus. Chaque étape est illustrée par des scénarios réels utilisant des outils courants : kubectl, Helm, GitHub Actions et un cluster local Kind ou un fournisseur cloud. À la fin, vous saurez appliquer ces modèles pour gérer des bases de données, des files d'attente ou d'autres services avec état dans votre propre environnement.
Commençons par comprendre l'état actuel de votre cluster et les caractéristiques spécifiques des StatefulSets.
Inventaire de la version et de l'environnement
Avant d'automatiser le déploiement des StatefulSets, établissez une base de référence : quelle version de Kubernetes vous exécutez, comment les StatefulSets se comportent dans cette version et quels outils sont disponibles. Cet inventaire évite les surprises ultérieures.
Vérifier la version de Kubernetes et les fonctionnalités
Exécutez :
kubectl version --short
Résultat attendu (exemple) :
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.3
Les StatefulSets sont stables depuis Kubernetes 1.9, mais les versions plus récentes ont introduit des politiques de gestion des pods par défaut et des mises à jour progressives améliorées. Notez la version de votre serveur pour l'aligner sur la documentation.
Inspecter les StatefulSets existants
Listez les StatefulSets actuels :
kubectl get statefulsets --all-namespaces
Exemple de résultat :
NAMESPACE NAME READY AGE
data postgres 3/3 15d
data redis 2/2 7d
Pour un StatefulSet spécifique, affichez son manifeste :
kubectl get statefulset postgres -n data -o yaml
Recherchez podManagementPolicy (par défaut OrderedReady) et updateStrategy. Ceux-ci régissent la façon dont les pods sont créés et mis à jour.
Identifier les prérequis
kubectlconfiguré avec les autorisations d'administrateur du cluster ou au niveau de l'espace de noms.- Une classe de stockage persistant disponible :
kubectl get storageclass. - Helm v3 si vous utilisez des charts Helm (optionnel mais recommandé).
- Un registre de conteneurs accessible depuis votre cluster.
Observation en lecture seule
Utilisez kubectl describe pour voir les événements et les conditions actuelles sans rien modifier :
kubectl describe statefulset postgres -n data
Recherchez Status, Replicas et les événements récents comme SuccessfulCreate ou FailedCreate. Cela vous indique si le StatefulSet est sain avant de le modifier.
Rayon d'impact et chemin de récupération
Demandez-vous toujours : « Si ce changement échoue, puis-je revenir en arrière ? » Pour les StatefulSets, un retour en arrière peut impliquer la restauration d'un instantané de base de données ou la réversion d'une version Helm. Assurez-vous d'avoir :
- Une sauvegarde des volumes persistants ou un calendrier d'instantanés.
- L'étiquette d'image ou la version du chart précédente enregistrée.
- Une procédure de retour en arrière testée (voir Modes de défaillance et récupération).
Environnement de test local
Pour l'expérimentation, utilisez un cluster local comme Kind ou Minikube. Voici un manifeste minimal de StatefulSet pour déployer une application de test (utilisant une image publique) :
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
name: web
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Appliquez-le et attendez qu'il soit prêt :
kubectl apply -f statefulset.yaml
kubectl rollout status statefulset/web
Résultat attendu :
statefulset rolling update complete 2 pods at revision web-...
Supprimez-le après le test :
kubectl delete statefulset web
kubectl delete pvc -l app=nginx
Vous disposez maintenant d'un environnement sécurisé pour vos essais.
Chemin de configuration sûr
L'automatisation du déploiement des StatefulSets nécessite un chemin de configuration qui minimise les risques. Nous utiliserons Helm pour la création de modèles et GitHub Actions pour le CI/CD, mais les concepts s'appliquent à tout outil de pipeline.
Pourquoi Helm pour les StatefulSets ?
Helm gère facilement les manifestes Kubernetes, y compris les StatefulSets. Il prend en charge les versions, le retour en arrière et les remplacements de valeurs. Installez Helm v3 et ajoutez un dépôt de charts si nécessaire.
Définir le StatefulSet dans un chart Helm
Créez un nouveau chart :
helm create my-stateful-app
Modifiez templates/statefulset.yaml. Voici un modèle pour une application avec état générique avec des réplicas et une image configurables :
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "my-stateful-app.fullname" . }}
spec:
serviceName: {{ include "my-stateful-app.fullname" . }}-headless
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "my-stateful-app.name" . }}
template:
metadata:
labels:
app: {{ include "my-stateful-app.name" . }}
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
env:
- name: DB_HOST
value: {{ .Values.database.host | quote }}
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: {{ .Values.persistence.size }}
Définissez des valeurs par défaut sensées dans values.yaml :
replicaCount: 3
image:
repository: myregistry/myapp
tag: "1.0.0"
service:
port: 8080
database:
host: "postgres.data.svc.cluster.local"
persistence:
size: 10Gi
Protéger les secrets
Ne mettez jamais de secrets dans values.yaml. Utilisez les Secrets Kubernetes ou des gestionnaires de secrets externes. Dans le pipeline, référencez les secrets à partir de variables d'environnement. Pour les tests locaux, utilisez un espace réservé et remplacez-le :
helm install myapp ./my-stateful-app \
--set database.password=$DB_PASSWORD
Dans GitHub Actions, stockez les secrets dans les paramètres du référentiel et injectez-les.
Configurer le pipeline CI/CD
Un pipeline typique pour les applications avec état comprend : lint, test, build, déploiement en staging, exécution de tests d'intégration et promotion en production avec approbation manuelle. Voici un extrait de workflow GitHub Actions :
name: CI/CD for StatefulSet
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: v3.12.0
- name: Lint chart
run: helm lint ./my-stateful-app
- name: Package chart
run: helm package ./my-stateful-app
- name: Deploy to staging
run: |
helm upgrade --install myapp ./my-stateful-app \
--namespace staging \
--set image.tag=${{ github.sha }} \
--set database.password=${{ secrets.STAGING_DB_PASSWORD }}
- name: Wait for rollout
run: kubectl rollout status statefulset/myapp -n staging --timeout=5m
- name: Run smoke tests
run: |
kubectl port-forward svc/myapp 8080:80 -n staging &
sleep 5
curl -f http://localhost:8080/health || exit 1
- name: Promote to production (manual)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
helm upgrade --install myapp ./my-stateful-app \
--namespace production \
--set image.tag=${{ github.sha }} \
--set database.password=${{ secrets.PROD_DB_PASSWORD }}
Vérification après le changement
Après le déploiement, vérifiez que les pods du StatefulSet ont démarré dans l'ordre et sont prêts :
kubectl get pods -n production -l app=myapp -o wide
Vérifiez à nouveau l'état du déploiement. Vérifiez également que les volumes persistants ont été créés correctement :
kubectl get pvc -n production
Assurez-vous que chaque pod possède une revendication de volume persistant unique.
Vérification et diagnostic
La vérification va au-delà du statut de déploiement. Vous devez confirmer que l'application fonctionne correctement et que les données persistent après les redémarrages.
Observer l'identité et l'ordre des pods
Les StatefulSets créent des pods avec des noms stables : myapp-0, myapp-1, etc. Vérifiez l'ordre de création :
kubectl get pods -n production -o name
Exemple :
pod/myapp-0
pod/myapp-1
pod/myapp-2
Si les pods ne sont pas créés dans l'ordre, vérifiez podManagementPolicy. La valeur par défaut OrderedReady garantit que myapp-0 est prêt avant que myapp-1 ne démarre. Si vous avez besoin d'une création parallèle, définissez podManagementPolicy: Parallel dans le manifeste, mais soyez conscient des implications pour la cohérence des données.
Consulter les journaux et les événements
Pour chaque pod, affichez les derniers journaux :
kubectl logs myapp-0 -n production --tail=20
Si un pod est en boucle de crash, utilisez --previous :
kubectl logs myapp-0 -n production --previous
Décrivez le pod pour voir les événements :
kubectl describe pod myapp-0 -n production
Recherchez les erreurs de montage de volume, les échecs d'extraction d'image ou les échecs de sonde.
Valider les données persistantes
Pour tester la persistance, écrivez un fichier dans le pod puis supprimez le pod :
kubectl exec -it myapp-0 -n production -- sh -c 'echo test > /data/test.txt'
kubectl delete pod myapp-0 -n production
Attendez que le pod soit recréé (le contrôleur StatefulSet le redémarrera) et vérifiez si le fichier existe toujours :
kubectl exec -it myapp-0 -n production -- cat /data/test.txt
Résultat attendu : test. Sinon, la revendication de volume ou la classe de stockage est peut-être mal configurée.
Vérification du réseau
Les StatefulSets utilisent souvent un service headless pour un DNS stable. Définissez un service headless :
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
spec:
clusterIP: None
selector:
app: myapp
ports:
- port: 80
Ensuite, depuis un autre pod, résolvez les noms :
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup myapp-0.myapp-headless.production.svc.cluster.local
Il devrait renvoyer l'adresse IP du pod. Cette identité stable est cruciale pour les services avec état comme les bases de données.
Supervision et métriques
Intégrez des outils de supervision comme Prometheus et Grafana. Exportez des métriques depuis votre application ou utilisez des sidecars. Au minimum, définissez des alertes pour kube_statefulset_status_replicas_ready inférieur à la valeur attendue. Un exemple de règle d'alerte Prometheus :
groups:
- name: statefulset
rules:
- alert: StatefulSetReplicasMismatch
expr: kube_statefulset_status_replicas_ready{namespace="production"} < kube_statefulset_replicas{namespace="production"}
for: 5m
labels:
severity: warning
annotations:
summary: "StatefulSet {{ $labels.statefulset }} has not enough ready replicas"
Modes de défaillance et récupération
Même avec l'automatisation, des échecs surviennent. Comprendre les modes de défaillance courants des StatefulSets vous prépare à récupérer rapidement.
Échec de la mise à jour progressive
Symptôme : kubectl rollout status expire ; certains pods restent en Pending ou CrashLoopBackOff.
Cause : La nouvelle image est défectueuse ou les contraintes de ressources ne sont pas satisfaites.
Récupération : Revenez à la révision précédente. Si vous utilisez Helm :
helm history myapp -n production
helm rollback myapp 2 -n production
Si vous utilisez des manifestes bruts, remettez l'étiquette d'image à la version précédente et appliquez. Surveillez la fin de la mise à jour progressive.
Échecs de liaison de volume persistant
Symptôme : Pods bloqués en Pending avec l'événement FailedBinding.
Cause : Aucun volume persistant ou classe de stockage correspondant.
Récupération : Vérifiez les classes de stockage et les volumes persistants disponibles :
kubectl get storageclass
kubectl get pv
Si le provisionnement dynamique ne fonctionne pas, assurez-vous que la classe de stockage existe et est définie par défaut. Ou préprovisionnez un PV avec la capacité et les modes d'accès correspondants.
Corruption ou perte de données
Symptôme : Erreurs d'application, données manquantes après le redémarrage du pod.
Cause : Revendications de volume mal configurées, suppression accidentelle de PVC ou utilisation d'un stockage non persistant.
Récupération : Restaurez à partir de la sauvegarde. Cela nécessite une stratégie de sauvegarde préalable. Par exemple, planifiez un CronJob pour prendre un instantané d'une base de données ou utilisez Velero pour les ressources et volumes Kubernetes. Dans votre pipeline, incluez une étape pour vérifier que les sauvegardes existent.
Cerveau divisé dans les applications avec état en cluster
Symptôme : Plusieurs réplicas agissent indépendamment, données incohérentes.
Cause : Partition réseau ou élection de leader incorrecte. Les StatefulSets avec services headless s'appuient sur des identités stables pour le quorum.
Récupération : Nécessite généralement une intervention manuelle : forcez la suppression du pod problématique, assurez la connectivité réseau et laissez l'application réélire un leader. Documentez ces procédures dans des runbooks.
Ordre de suppression et de recréation des pods
Symptôme : Le pod myapp-1 est prêt avant myapp-0 après une réduction puis une augmentation de l'échelle.
Cause : Les opérations de mise à l'échelle peuvent ne pas suivre un ordre strict si podManagementPolicy: Parallel est défini ou si vous supprimez manuellement des pods.
Récupération : Vérifiez la politique ; si l'ordre est requis, définissez-la à OrderedReady. Évitez les suppressions manuelles de pods sauf nécessité ; utilisez plutôt kubectl scale statefulset.
Vérification de la récupération
Après toute récupération, exécutez les étapes de vérification de la section précédente : vérifiez l'état des pods, les journaux, les données persistantes et l'identité réseau. Documentez l'incident et mettez à jour le pipeline pour détecter des problèmes similaires plus tôt (par exemple, ajoutez un contrôle de santé qui teste la persistance des données).
Pièges courants et comment les éviter
De nombreuses équipes trébuchent avec l'automatisation des StatefulSets. Voici les pièges les plus fréquents et des conseils pratiques.
Utiliser des Deployments au lieu de StatefulSets pour les applications avec état
Pourquoi cela arrive : Les développeurs habitués aux applications sans état utilisent les Deployments par réflexe.
Comment l'éviter : Reconnaissez quand votre application a besoin d'une identité stable, de stockage ou d'un déploiement ordonné. Utilisez des StatefulSets pour les bases de données, les files d'attente de messages et d'autres services avec état. Si votre application peut utiliser un Deployment avec un volume partagé, testez soigneusement.
Ignorer la politique de gestion des pods
Pourquoi cela arrive : La valeur par défaut OrderedReady peut ralentir la mise à l'échelle ; les équipes passent à Parallel sans en comprendre les conséquences.
Comment l'éviter : Évaluez les exigences de votre application. Le mode parallèle peut améliorer la vitesse pour des pods avec état mais quasi sans état, mais peut casser le clustering. Testez en staging avant de modifier.
Ne pas gérer correctement les revendications de volume persistant
Pourquoi cela arrive : La suppression d'un StatefulSet ne supprime pas automatiquement les PVC, ce qui entraîne des volumes orphelins et un gaspillage de ressources.
Comment l'éviter : Gérez explicitement les PVC. Utilisez une politique pour supprimer les PVC lorsque le StatefulSet est supprimé si les données ne sont pas nécessaires, ou utilisez une politique de rétention pour les données. Dans Helm, utilisez des hooks pour le nettoyage.
Gestion des secrets dans les pipelines
Pourquoi cela arrive : Codage en dur des secrets dans les manifestes ou les fichiers de valeurs par commodité.
Comment l'éviter : Utilisez toujours des références de secrets. Dans le CI/CD, utilisez des gestionnaires de secrets (HashiCorp Vault, magasins de secrets du fournisseur cloud) et injectez-les au moment du déploiement. Ne journalisez jamais les secrets.
Absence de plan de retour en arrière
Pourquoi cela arrive : Les équipes supposent que les déploiements réussiront toujours et ne se préparent pas à l'échec.
Comment l'éviter : Avant chaque version, enregistrez la version actuelle et testez les commandes de retour en arrière. Incluez le retour en arrière dans les runbooks et automatisez avec helm rollback ou équivalent.
Ne pas superviser la santé des StatefulSets
Pourquoi cela arrive : La supervision se concentre sur les métriques des charges de travail sans état, manquant des signaux spécifiques aux états.
Comment l'éviter : Supervisez les réplicas prêts, l'utilisation des volumes et les redémarrages des pods. Définissez des alertes comme indiqué précédemment.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant et après chaque exécution CI/CD de StatefulSet. Attribuez un responsable unique pour chaque élément et définissez une fréquence de révision.
| Élément | Responsable | Fréquence | Commande de vérification | Résultat attendu |
|---|---|---|---|---|
| Vérifier la prise en charge de la version Kubernetes | Ingénieur plateforme (ex. Alex Chen) | Mensuellement ou lors d'une mise à niveau du cluster | kubectl version --short | Version >= 1.19, feature gates corrects |
| Confirmer l'existence de la classe de stockage et des PVC | Ingénieur DevOps (ex. Priya Shah) | Avant chaque déploiement | kubectl get sc,pvc -n production | PVC liés, aucun en attente |
| Sauvegarder les données persistantes | Administrateur de base de données (ex. Sam Lee) | Avant chaque déploiement et chaque nuit | velero backup get ou dump de base de données | Sauvegarde terminée avec succès |
| Réviser les modifications du manifeste StatefulSet | Chef d'équipe (ex. Jordan Smith) | Chaque PR | Revue de code approuvée | Le diff montre uniquement les modifications prévues |
| Exécuter le pipeline sur staging | Pipeline CI/CD (automatisé) | À chaque fusion vers main | Statut GitHub Actions | Tous les tests passent |
| Vérifier le statut du déploiement | Responsable de version (ex. Taylor Wilson) | Après le déploiement en staging | kubectl rollout status statefulset/myapp -n staging --timeout=5m | "statefulset rolling update complete" |
| Vérifier l'identité et l'ordre des pods | Responsable de version | Après le déploiement | kubectl get pods -n staging -l app=myapp -o wide | Pods myapp-0, myapp-1, myapp-2 prêts dans l'ordre |
| Tester la persistance en staging | Ingénieur QA (ex. Morgan Brown) | À chaque version | Écrire un fichier, supprimer le pod, lire le fichier | Le fichier persiste |
| Approbation manuelle pour la production | Product Owner (ex. Casey Davis) | À chaque version | Approuver dans le pipeline | Approbation accordée |
| Supervision post-déploiement | SRE (ex. Riley Garcia) | 24 heures après le déploiement en production | Vérifier les alertes Prometheus | Aucune alerte critique |
| Examiner les journaux d'incidents et mettre à jour les runbooks | Chef d'équipe | Hebdomadaire | Réunion d'examen des incidents | Runbooks mis à jour |
Chaque élément doit avoir un responsable clair chargé de l'exécution et de la résolution des problèmes si la vérification échoue. Révisez la liste de contrôle tous les trimestres pour l'adapter aux nouveaux risques.
Conclusion
L'automatisation du CI/CD pour les StatefulSets Kubernetes exige une attention particulière aux caractéristiques avec état : identités stables, stockage persistant et opérations ordonnées. Ce guide a fourni une procédure pas à pas pratique : de l'inventaire de l'environnement à la configuration sûre, en passant par la vérification, la récupération après échec et les pièges courants. Nous avons inclus des commandes concrètes, des manifestes, des exemples de pipeline et une liste de contrôle avec des responsables clairs.
Pour commencer, choisissez un StatefulSet dans votre environnement et appliquez les étapes d'observation. Enregistrez l'état actuel, concevez un chart Helm et un pipeline, et testez le retour en arrière dans un espace de noms de staging. Rappelez-vous les principes directeurs : observer avant de modifier, protéger les secrets, limiter le rayon d'impact, vérifier minutieusement et documenter les chemins de récupération.
En suivant ces pratiques, vous pouvez réaliser des déploiements automatisés fiables pour les applications avec état sur Kubernetes, réduisant ainsi les risques de temps d'arrêt et de perte de données.