Liveness, Readiness et Startup Probe dans Kubernetes
1. Aperçu
Quand vous exécutez une application sur Kubernetes, le cluster ne sait pas automatiquement si votre pod « vit » ou « est prêt à recevoir du trafic » — il doit en faire la demande via une probe. Cet article explique les différences entre liveness, readiness et startup probe, avec des exemples de configuration de Spring Boot Actuator et de Deployment YAML. À la fin de la lecture, vous saurez configurer correctement les probes pour un vrai service comme OrderService sans créer une boucle de redémarrage inutile.
2. Pourquoi avez-vous besoin de probes
Par défaut, Kubernetes sait seulement si le processus dans le container est en cours d’exécution (container status Running) ou non. Il ne sait pas si l’application intérieure est en deadlock, a perdu la connexion à la base de données, ou est encore en cours de démarrage.
Les conséquences sans probes :
- Un pod figé (deadlock) reçoit toujours du trafic → timeouts en masse.
- Un pod vient de démarrer, n’a pas encore connecté la base de données, et est déjà ajouté à la liste d’endpoints du Service → erreurs 500.
Trois types de probes résolvent trois problèmes différents :
| Probe | Répond à la question | En cas d’échec |
|---|---|---|
| Liveness | Le container est-il encore vivant ? | Kubernetes redémarre le container |
| Readiness | Le container est-il prêt à recevoir du trafic ? | Kubernetes retire le pod de l’endpoint du Service (sans redémarrage) |
| Startup | Le container a-t-il fini de démarrer ? | Kubernetes attend, désactive temporairement les probes liveness/readiness |
3. Liveness probe
La liveness probe répond : « ce processus est-il dans un état irrécupérable ? ». Si la probe échoue plus de failureThreshold fois, kubelet tue et redémarre le container.
3.1. Ajouter Spring Boot Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management.endpoint.health.probes.enabled=true
management.endpoints.web.exposure.include=health,info
La ligne management.endpoint.health.probes.enabled=true active deux endpoints : /actuator/health/liveness et /actuator/health/readiness, conformes aux attentes de Kubernetes.
3.2. Déclarer dans le Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 3
initialDelaySeconds: 20: attend 20s après le démarrage du container avant de commencer les probes.periodSeconds: 10: appelle la probe toutes les 10s.failureThreshold: 3: considère le pod comme mort après 3 échecs consécutifs → redémarrage.
Remarque : La probe liveness ne doit vérifier que « l’application s’exécute-t-elle encore ? », et ne doit pas vérifier les dépendances externes (base de données, Redis…). Si la base de données tombe en panne et que la liveness échoue en conséquence, Kubernetes redémarrera le pod continuellement sans résoudre quoi que ce soit — c’est une erreur très courante.
4. Readiness probe
La readiness probe répond : « le pod est-il prêt à traiter les requêtes ? ». En cas d’échec, le pod est retiré de l’endpoint du Service — le trafic n’est plus envoyé, mais le container n’est pas redémarré.
4.1. Indicateur de readiness personnalisé
Supposons que OrderService doit se connecter à PaymentGateway avant d’être prêt :
@Component
public class PaymentGatewayReadinessIndicator implements HealthIndicator {
private final PaymentGatewayClient paymentGatewayClient;
public PaymentGatewayReadinessIndicator(PaymentGatewayClient paymentGatewayClient) {
this.paymentGatewayClient = paymentGatewayClient;
}
@Override
public Health health() {
if (paymentGatewayClient.isConnected()) {
return Health.up().withDetail("gateway", "connected").build();
}
return Health.down().withDetail("gateway", "unreachable").build();
}
}
Pour inclure cet indicateur dans le groupe readiness (sans affecter liveness), déclarez le groupe :
management.endpoint.health.group.readiness.include=readinessState,paymentGateway
health()retourneHealth.down()quandPaymentGatewayClientn’est pas connecté — la readiness probe échoue, le pod ne reçoit pas de trafic jusqu’à ce que la gateway soit prête.- Spring nomme automatiquement le bean
paymentGatewayReadinessIndicatorcomme clépaymentGatewaydans la réponse health.
4.2. Test pour l’indicateur
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
class PaymentGatewayReadinessIndicatorTest {
@Test
void shouldReportDownWhenGatewayNotConnected() {
PaymentGatewayClient client = mock(PaymentGatewayClient.class);
when(client.isConnected()).thenReturn(false);
PaymentGatewayReadinessIndicator indicator = new PaymentGatewayReadinessIndicator(client);
Health health = indicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("gateway", "unreachable");
}
}
mock(PaymentGatewayClient.class)simule la dépendance externe, sans avoir besoin d’une connexion réelle.assertThat(health.getStatus())confirme que le statut estDOWNquand la gateway n’est pas connectée — c’est le comportement attendu de la readiness.
4.3. Déclarer readiness dans le Deployment
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 3
successThreshold: 1
successThreshold: 1: un seul succès de probe suffit pour considérer le pod comme prêt (différent de liveness, généralement pas besoin de définir ce champ car la valeur par défaut est déjà 1).periodSeconds: 5plus court que liveness parce que readiness doit réagir rapidement aux changements d’état des dépendances.
5. Startup probe
Pour une application à démarrage lent (chargement de gros caches, exécution de migrations de base de données), si vous utilisez uniquement liveness avec un initialDelaySeconds fixe, vous devez deviner un nombre suffisamment grand — c’est facile à se tromper et cela gaspille du temps d’attente à chaque redémarrage.
La startup probe résout ce problème : tant que la startup probe n’a pas réussi, Kubernetes désactive temporairement les probes liveness et readiness, évitant un arrêt injustifié quand l’app démarre légitimement.
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 10
failureThreshold: 3
startupProbeavecfailureThreshold: 30etperiodSeconds: 10→ permet à l’app de démarrer jusqu’à 300s (30 × 10s) avant d’être considérée comme échouée.- Après le premier succès de
startupProbe, Kubernetes bascule vers la surveillance delivenessProbeavec un seuil plus petit (3 fois × 10s = 30s) — réagit rapidement aux vrais problèmes en fonctionnement normal.
Remarque : Si votre application démarre rapidement (quelques secondes, comme une API REST simple sans chargement de gros cache), vous n’avez pas besoin de déclarer
startupProbe— l’ajouter ne ferait que allonger le YAML sans bénéfice évident.
6. Combiner les trois dans un Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
periodSeconds: 5
failureThreshold: 3
Le flux de fonctionnement quand un nouveau pod est créé :
- Le container démarre, Kubernetes commence immédiatement à appeler
startupProbe(pas d’initialDelaySecondscar la startup gère elle-même l’attente). - Pendant ce temps,
livenessProbeetreadinessProbene s’exécutent pas encore. - Quand
startupProberetourne HTTP 200 pour la première fois, Kubernetes arrête la startup probe et commence à exécuter liveness et readiness en parallèle. - Readiness échoue → le pod est retiré du Service, le trafic n’est plus envoyé, mais le container reste actif.
- Liveness échoue → le container est tué, Kubernetes crée un nouveau container (même pod), le processus recommence à l’étape 1.
Vérifiez l’état réel des probes avec kubectl describe pod :
kubectl describe pod order-service-7d9f8c6b5-xk2pq
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Events:
Type Reason Age From Message
Warning Unhealthy 2m kubelet Readiness probe failed: HTTP probe failed with statuscode: 503
La ligne Readiness probe failed indique que readiness échoue — vérifiez les logs de l’application ou appelez directement /actuator/health/readiness pour voir quel détail est DOWN.
7. Erreurs courantes
- Utiliser le même endpoint pour liveness et readiness : quand une dépendance externe (DB, cache) tombe en panne, les deux probes échouent ensemble → le pod redémarre continuellement (crash loop) même si l’application principale fonctionne bien. Séparez clairement
/actuator/health/liveness(vérifie uniquement l’interne) et/actuator/health/readiness(vérifie aussi les dépendances). initialDelaySecondstrop petit pour une app à démarrage lent : la liveness probe échoue pendant que l’app charge, créant une boucle de redémarrage infinie. Solution : utilisezstartupProbeau lieu d’augmenter arbitrairementinitialDelaySeconds.periodSeconds×failureThresholdtrop grand : un pod défaillant réel met plusieurs minutes à être détecté, affectant le SLA.- La readiness probe appelle un service downstream sans importance : par exemple, un service de journalisation, si ce service tombe en panne, tout
OrderServiceest considéré comme not-ready à tort, même si la fonctionnalité principale fonctionne bien.
8. Conclusion
Les trois types de probes servent trois objectifs distincts : startupProbe protège l’application pendant le démarrage lent, livenessProbe détecte les deadlocks pour que Kubernetes redémarre, et readinessProbe gère le trafic en fonction de l’état réel des dépendances. Le principe le plus important : ne laissez pas la liveness probe dépendre de systèmes externes — cela transformerait une panne en aval en crash loop de votre propre service. Configurer correctement ces trois probes aide le cluster à se rétablir en douceur, réduisant considérablement les temps d’arrêt lors du déploiement ou lors de problèmes d’infrastructure.