Comment Effectuer des Mises à Jour Progressives Sans Interruption (Zero-Downtime) dans Kubernetes Deployments
Introduction
Dans les architectures modernes de microservices, maintenir une disponibilité continue lors des mises à jour d'applications est une exigence non négociable. Les Deployments Kubernetes simplifient ce processus en offrant des Mises à Jour Progressives (Rolling Updates) automatisées, une stratégie conçue pour remplacer progressivement les anciennes versions des Pods par de nouvelles.
Cependant, atteindre une véritable absence d'interruption nécessite plus que la configuration par défaut de Kubernetes. Cela impose une coordination minutieuse entre le manifeste du Deployment, les points d'accès de santé de l'application et le processus de terminaison contrôlée. Ce guide propose une approche complète, étape par étape, pour configurer les Deployments Kubernetes afin de garantir que les mises à jour d'applications soient transparentes et invisibles pour l'utilisateur final.
Nous couvrirons le rôle essentiel des sondes de préparation (readiness probes), comment ajuster les paramètres de la stratégie de déploiement (maxSurge et maxUnavailable), et les meilleures pratiques pour la terminaison des applications afin d'éliminer les interruptions de service pendant les transitions de déploiement.
Prérequis pour l'Absence d'Interruption (Zero-Downtime)
Avant de configurer le manifeste Kubernetes, l'application sous-jacente doit adhérer à certains principes pour supporter les déploiements sans interruption :
- Rétrocompatibilité de l'Application : Pendant la courte période où les anciennes et les nouvelles versions de l'application s'exécutent simultanément, elles doivent être compatibles avec les ressources partagées (bases de données, files d'attente, caches).
- Idempotence : Les opérations qui pourraient être gérées par les deux versions doivent être répétables sans effets secondaires négatifs.
- Terminaison Contrôlée (Graceful Termination) : L'application doit être programmée pour reconnaître le signal
SIGTERMenvoyé par Kubernetes et cesser de manière contrôlée d'accepter de nouvelles connexions tout en terminant les requêtes en cours avant de se terminer.
Comprendre la Stratégie de Mise à Jour Progressive (Rolling Update) de Kubernetes
Par défaut, Kubernetes Deployments utilise la stratégie RollingUpdate. Cette méthode garantit que l'ancienne version de l'application n'est pas entièrement arrêtée avant que la nouvelle version ne soit opérationnelle, gérant la transition à l'aide de deux paramètres principaux :
| Paramètre | Description | Impact sur l'Absence d'Interruption |
|---|---|---|
maxSurge |
Définit le nombre maximum de Pods qui peuvent être créés en plus du nombre désiré de réplicas. Peut être un nombre absolu ou un pourcentage (par défaut : 25%). | Contrôle la vitesse du déploiement et assure une augmentation temporaire de la capacité. |
maxUnavailable |
Définit le nombre maximum de Pods qui peuvent être indisponibles pendant la mise à jour. Peut être un nombre absolu ou un pourcentage (par défaut : 25%). | Crucial pour l'absence d'interruption. Le régler à 0% signifie qu'aucun Pod de service n'est terminé tant que les nouveaux Pods ne sont pas complètement Ready. |
Stratégie Recommandée pour l'Absence d'Interruption
Pour la plus haute disponibilité, la meilleure configuration est souvent de garantir une perte de capacité nulle :
maxUnavailable: 0(Assure que la capacité ne tombe jamais en dessous du niveau souhaité).maxSurge: 1ou25%(Permet à la capacité de dépasser brièvement la cible, garantissant qu'un nouveau Pod est prêt avant qu'un ancien ne soit arrêté).
Étape 1 : Implémentation des Sondes de Préparation (Readiness Probes)
La Sonde de Préparation (Readiness Probe) est le mécanisme le plus important pour garantir des mises à jour sans interruption. Kubernetes s'appuie sur cette sonde pour déterminer si un nouveau Pod est prêt à recevoir le trafic utilisateur et si un ancien Pod sert toujours activement du trafic.
Liveness vs. Readiness
- Sonde de Vivacité (Liveness Probe) : Indique à Kubernetes si le conteneur est sain et fonctionnel. Si elle échoue, le conteneur est redémarré.
- Sonde de Préparation (Readiness Probe) : Indique à Kubernetes si le conteneur est prêt à servir des requêtes. Si elle échoue, le Pod est retiré des points d'accès du Service associé, détournant le trafic loin de lui jusqu'à ce qu'il soit prêt.
Pour les mises à jour progressives, la Sonde de Préparation est utilisée pour contrôler la transition. Kubernetes ne procédera pas à la terminaison d'un ancien Pod tant qu'un Pod nouvellement créé n'aura pas réussi son test de préparation.
# Extrait de deployment.yaml
spec:
containers:
- name: my-app
image: myregistry/my-app:v2.0
ports:
- containerPort: 8080
# --- Configuration de la Sonde de Préparation ---
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15 # Délai avant la première tentative de sonde
periodSeconds: 5 # Fréquence de vérification
timeoutSeconds: 3
failureThreshold: 3 # Nombre d'échecs consécutifs pour marquer le Pod comme non prêt
# --- Configuration de la Sonde de Vivacité (Vérification de Santé Standard) ---
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
Astuce : Assurez-vous que le point d'accès
/health/readyde votre application renvoie un code de succès (HTTP 200-299) uniquement lorsque l'initialisation, les connexions à la base de données et les autres dépendances externes sont pleinement opérationnelles.
Étape 2 : Configuration de la Stratégie de Déploiement
Pour imposer une absence d'interruption réelle, nous configurons explicitement la stratégie de mise à jour progressive pour empêcher toute baisse du nombre de réplicas disponibles.
Dans cette configuration, Kubernetes créera d'abord un nouveau Pod (maxSurge: 1). Une fois que le nouveau Pod aura réussi sa sonde de préparation, alors seulement Kubernetes terminera un ancien Pod. Puisque maxUnavailable est à 0, la capacité de service ne tombe jamais en dessous du nombre cible de réplicas.
# Extrait de deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-deployment
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
# Assure que la capacité ne tombe jamais en dessous du nombre de réplicas désiré (4)
maxUnavailable: 0
# Permet la création d'un Pod supplémentaire pendant le déploiement
maxSurge: 1
template:
# ... spécification du conteneur ...
Étape 3 : Assurer une Terminaison Contrôlée (Graceful Termination)
Même avec des sondes de préparation robustes, si l'application s'arrête instantanément à la réception du signal de terminaison, elle risque de perdre les requêtes en cours.
Kubernetes suit une séquence de terminaison spécifique :
- Le Pod est marqué comme Terminant (Terminating).
- Le Pod est retiré des points d'accès du Service (le trafic ne lui est plus acheminé).
- Le hook preStop (s'il est défini) est exécuté.
- Le conteneur reçoit le signal
SIGTERM. - Kubernetes attend la durée définie par
terminationGracePeriodSeconds(par défaut : 30 secondes). - Si le conteneur est toujours en cours d'exécution, il reçoit un
SIGKILLnon négociable.
Pour assurer un arrêt contrôlé, l'application doit gérer SIGTERM, et terminationGracePeriodSeconds doit être suffisamment long pour que l'application termine les requêtes existantes.
# Extrait de deployment.yaml, dans la spécification du conteneur
terminationGracePeriodSeconds: 45 # Délai augmenté pour l'arrêt contrôlé
containers:
- name: my-app
image: myregistry/my-app:v2.0
lifecycle:
preStop:
exec:
# Exemple : Exécution d'un script pour vider immédiatement les connexions
command: ["/bin/sh", "-c", "sleep 10"]
Meilleure Pratique : Le temps entre l'échec de la Sonde de Préparation du Pod (Étape 2) et la réception de
SIGTERM(Étape 4) est critique. Si votre application gère correctementSIGTERM, définir unterminationGracePeriodSecondslégèrement plus long (par exemple, 45 ou 60 secondes) évite les arrêts brutaux.
Étape 4 : Effectuer et Surveiller la Mise à Jour
Une fois que votre manifeste de Deployment inclut la stratégie optimisée et des sondes robustes, effectuer la mise à jour est simple.
-
Mettre à Jour le Tag de l'Image : Modifiez votre manifeste de déploiement pour refléter la nouvelle version de l'image (par exemple, de
v2.0àv2.1). -
Appliquer la Configuration :
bash kubectl apply -f deployment.yamlAlternativement, vous pouvez patcher l'image directement :
bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1 -
Surveiller le Statut du Déploiement : Observez Kubernetes progresser à travers les étapes, en vérifiant que le nombre de Pods prêts ne tombe jamais en dessous du nombre désiré.
bash kubectl rollout status deployment/my-web-deployment -
Vérifier la Disponibilité des Pods : Observez le statut des Pods pour confirmer que les anciens Pods (v2.0) sont terminés de manière contrôlée seulement après que les nouveaux Pods (v2.1) soient complètement prêts.
bash kubectl get pods -l app=my-web-deployment -w
Considérations Avancées
Utilisation des Pod Disruption Budgets (PDBs)
Alors qu'une stratégie de déploiement gère les mises à jour volontaires, un Pod Disruption Budget (PDB) garantit qu'un nombre minimum de Pods est disponible même lors de disruptions imprévues (par exemple, maintenance de nœuds, mises à niveau de cluster). Bien que les PDBs ne contrôlent pas directement la vitesse des mises à jour progressives, ils agissent comme un filet de sécurité.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 75% # Assure qu'au moins 75% des réplicas sont toujours disponibles
selector:
matchLabels:
app: my-web-deployment
L'Importance du Délai Initial
Si votre application met du temps à démarrer (par exemple, chargement de gros fichiers de configuration ou établissement de caches), assurez-vous que initialDelaySeconds dans votre Sonde de Préparation est suffisamment long. Si la sonde vérifie trop tôt et échoue, le Pod sera marqué comme non sain et potentiellement bloqué dans une boucle de crash, arrêtant tout le déploiement.
Conclusion
Atteindre une mise à jour progressive sans interruption (zero-downtime) dans Kubernetes est une combinaison de configuration de plateforme robuste et de développement d'application discipliné. En exploitant correctement les Sondes de Préparation pour signaler l'état opérationnel, en ajustant la stratégie de Déploiement (maxUnavailable: 0) pour maintenir la capacité, et en implémentant des gestionnaires de terminaison contrôlée, vous pouvez garantir que les mises à jour d'applications sont effectuées de manière fiable sans interrompre le service à vos utilisateurs. Testez toujours votre processus de mise à jour de manière approfondie dans un environnement de staging pour valider la période de grâce de terminaison et la logique des sondes.