
CrashLoopBackOff signifie qu’un conteneur plante, redémarre, puis replante
en boucle. Kubernetes augmente le délai entre chaque redémarrage
(10 s → 20 s → 40 s → … → 5 min max) pour éviter de surcharger le nœud.
Ce guide vous donne une méthodologie en 4 étapes pour identifier la cause
et corriger le problème.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre le mécanisme du backoff exponentiel et pourquoi Kubernetes augmente le délai entre les redémarrages
- Identifier les 6 causes principales d’un CrashLoopBackOff
- Appliquer une méthodologie de diagnostic reproductible en 4 étapes
- Utiliser
kubectl logs --previousetkubectl describe podpour trouver la cause réelle - Reproduire et corriger un CrashLoopBackOff sur un cluster de test
Prérequis
Section intitulée « Prérequis »- Un cluster Kubernetes fonctionnel (v1.28+)
kubectlconfiguré et connecté au cluster- Des droits de lecture sur les pods, événements et logs
- Connaissances de base sur les Pods et les probes
Qu’est-ce qu’un CrashLoopBackOff ?
Section intitulée « Qu’est-ce qu’un CrashLoopBackOff ? »CrashLoopBackOff n’est pas une phase du Pod. C’est un état d’attente
visible dans la colonne STATUS de kubectl get pods lorsqu’un conteneur
échoue puis redémarre en boucle avec backoff. Selon le moment où vous
observez le Pod, sa phase peut rester Running, mais ce n’est pas
systématique — le point clé est qu’un conteneur redémarre en boucle.
Le backoff exponentiel
Section intitulée « Le backoff exponentiel »Quand un conteneur plante, le kubelet applique un délai croissant avant chaque nouveau redémarrage :
| Tentative | Délai avant redémarrage | Temps total écoulé |
|---|---|---|
| 1re | 10 secondes | 10 s |
| 2e | 20 secondes | 30 s |
| 3e | 40 secondes | 1 min 10 s |
| 4e | 80 secondes | 2 min 30 s |
| 5e | 160 secondes | 5 min 10 s |
| 6e+ | 300 secondes (maximum) | +5 min par tentative |
Si le conteneur reste stable pendant 10 minutes, le compteur de backoff est réinitialisé.
Les 6 causes principales
Section intitulée « Les 6 causes principales »Voici les causes les plus fréquentes rencontrées en pratique :
| # | Cause | Symptôme typique | Où chercher |
|---|---|---|---|
| 1 | Erreur applicative | Exception, panic, segfault dans les logs | kubectl logs |
| 2 | Configuration manquante | Variable d’env absente, fichier de config introuvable | kubectl describe pod (env, volumes) |
| 3 | OOMKilled | Le conteneur dépasse sa limite mémoire | kubectl describe pod → Last State: OOMKilled |
| 4 | Probe mal configurée (liveness ou startup) | Unhealthy, Killing, redémarrages répétés | kubectl describe pod → Events, définition des probes |
| 5 | Commande ou entrypoint invalide | Le conteneur s’arrête immédiatement avec exit code 126 ou 127 | kubectl describe pod, kubectl logs --previous |
| 6 | Dépendance externe indisponible | La base de données ou l’API n’est pas accessible | kubectl logs (timeout, connection refused) |
Méthodologie de diagnostic en 4 étapes
Section intitulée « Méthodologie de diagnostic en 4 étapes »-
Identifier le pod en CrashLoopBackOff
Listez les pods et repérez ceux dont le STATUS est
CrashLoopBackOffou dont le compteurRESTARTSaugmente :Fenêtre de terminal kubectl get pods -A | grep -E 'CrashLoop|Error|BackOff'Notez le nom du pod, son namespace et le nombre de RESTARTS.
-
Lire les logs du conteneur crashé
La commande la plus importante est
kubectl logs --previous, qui affiche les logs de l’exécution précédente (celle qui a planté) :Fenêtre de terminal kubectl logs <pod> -n <namespace> --previousSi le pod contient plusieurs conteneurs, précisez le conteneur :
Fenêtre de terminal kubectl logs <pod> -n <namespace> -c <conteneur> --previousCherchez des indices :
Exception,Error,panic,Traceback,connection refused,OOM,permission denied. -
Inspecter la description du pod
Fenêtre de terminal kubectl describe pod <pod> -n <namespace>Les sections à regarder en priorité :
- Last State : la raison de l’arrêt précédent (
OOMKilled,Error,Completed) - Exit Code :
0= arrêt normal,1= erreur applicative,137= OOMKilled ou SIGKILL,139= segfault - Events :
Unhealthy(probe échouée),BackOff,Pulling - Containers → Args/Command : la commande de démarrage est-elle correcte ?
- Containers → Env : les variables d’environnement sont-elles présentes ?
- Containers → Mounts : les volumes sont-ils montés correctement ?
- Last State : la raison de l’arrêt précédent (
-
Corriger et vérifier
Selon la cause identifiée :
Cause Action corrective Erreur applicative Corriger le code ou la config, redéployer Config manquante Ajouter le ConfigMap/Secret, vérifier les noms OOMKilled Augmenter resources.limits.memoryProbe mal configurée Augmenter initialDelaySeconds,timeoutSeconds, ou ajouter une startup probeCommande/entrypoint invalide Vérifier command:etargs:dans le manifesteDépendance externe Vérifier la connectivité, ajouter un init container Après correction, vérifiez que le pod est stable :
Fenêtre de terminal kubectl get pods -n <namespace> -wLe flag
-w(watch) permet de suivre l’évolution en temps réel. Le pod doit passer àRunninget le compteur de RESTARTS ne doit plus augmenter.
Exemple pratique : reproduire un CrashLoopBackOff
Section intitulée « Exemple pratique : reproduire un CrashLoopBackOff »Pour bien comprendre le mécanisme, créons volontairement un pod qui crashe.
Cas 1 : erreur applicative (exit code 1)
Section intitulée « Cas 1 : erreur applicative (exit code 1) »apiVersion: v1kind: Podmetadata: name: crash-exit-error namespace: defaultspec: restartPolicy: Always containers: - name: app image: busybox:1.37 command: ["sh", "-c", "echo 'Application démarrée'; sleep 2; echo 'Erreur fatale!'; exit 1"]kubectl apply -f- <<'EOF'apiVersion: v1kind: Podmetadata: name: crash-exit-error namespace: defaultspec: restartPolicy: Always containers: - name: app image: busybox:1.37 command: ["sh", "-c", "echo 'Application démarrée'; sleep 2; echo 'Erreur fatale!'; exit 1"]EOFAttendez 30 secondes puis observez :
kubectl get pods crash-exit-error -wVous verrez le STATUS passer de Running à Error puis à
CrashLoopBackOff, avec le compteur RESTARTS qui augmente.
Diagnostic :
# Logs de l'exécution qui a crashékubectl logs crash-exit-error --previous
# Description avec exit codekubectl describe pod crash-exit-error | grep -A5 "Last State"Cas 2 : OOMKilled (dépassement mémoire)
Section intitulée « Cas 2 : OOMKilled (dépassement mémoire) »Pour provoquer un vrai OOMKill, le conteneur doit allouer de la mémoire
au-delà de sa limite. Un simple dd vers /dev/null consomme du CPU, pas de
la RAM. Voici un exemple qui alloue réellement de la mémoire avec un tail
grossier :
kubectl apply -f- <<'EOF'apiVersion: v1kind: Podmetadata: name: crash-oom namespace: defaultspec: restartPolicy: Always containers: - name: app image: python:3.13-slim command: ["python3", "-c", "data = []; [data.append('x' * 10**6) for _ in range(500)]"] resources: limits: memory: "50Mi"EOFLe script Python alloue des blocs de 1 Mo en boucle jusqu’à dépasser la limite de 50 Mi, ce qui déclenche un OOMKill.
Diagnostic :
kubectl describe pod crash-oom | grep -A5 "Last State"Vous verrez Reason: OOMKilled et Exit Code: 137.
Nettoyage
Section intitulée « Nettoyage »kubectl delete pod crash-exit-error crash-oom --force --grace-period=0Les exit codes essentiels
Section intitulée « Les exit codes essentiels »Les exit codes aident à identifier rapidement la nature du crash :
| Exit code | Signification | Cause probable |
|---|---|---|
0 | Arrêt normal | Le conteneur s’est terminé volontairement — si restartPolicy: Always, il sera relancé |
1 | Erreur générique | Bug applicatif, exception non gérée |
2 | Mauvais usage de commande shell | Commande ou argument invalide dans command: |
126 | Permission denied | Le binaire n’est pas exécutable |
127 | Command not found | Le binaire n’existe pas dans l’image |
137 | SIGKILL (128 + 9) | Processus tué par SIGKILL — souvent un OOMKill, mais pas exclusivement |
139 | SIGSEGV (128 + 11) | Segmentation fault dans l’application |
143 | SIGTERM (128 + 15) | Arrêt gracieux demandé par Kubernetes |
Cas particuliers
Section intitulée « Cas particuliers »CrashLoopBackOff avec logs vides
Section intitulée « CrashLoopBackOff avec logs vides »Si kubectl logs --previous ne retourne rien, c’est souvent que le conteneur
a planté avant de produire un output. Causes possibles :
- Le binaire n’existe pas dans l’image (exit code 127)
- Le point d’entrée n’est pas exécutable (exit code 126)
- OOMKill immédiat (exit code 137)
Dans ce cas, utilisez kubectl describe pod pour lire l’exit code et
les événements.
CrashLoopBackOff causé par une liveness probe
Section intitulée « CrashLoopBackOff causé par une liveness probe »Si les événements montrent Unhealthy suivi de Killing, le conteneur
fonctionne mais la liveness probe considère qu’il est mort :
Warning Unhealthy 10s kubelet Liveness probe failed: HTTP probe failed with statuscode: 503Normal Killing 10s kubelet Container app failed liveness probe, will be restartedLa solution est de revoir la configuration de la probe :
- Augmenter
initialDelaySecondssi l’application met du temps à démarrer - Augmenter
timeoutSecondssi le endpoint est lent - Utiliser une startup probe pour les démarrages longs
Consultez le guide sur les probes Kubernetes pour les bonnes pratiques de configuration.
CrashLoopBackOff sur un init container
Section intitulée « CrashLoopBackOff sur un init container »Les init containers s’exécutent une fois avant le conteneur principal. Si un
init container crashe, le pod n’atteint jamais l’état Running et vous verrez
Init:CrashLoopBackOff dans le STATUS.
Diagnostic identique, en précisant le conteneur :
kubectl logs <pod> -c <init-container> --previousDépannage rapide
Section intitulée « Dépannage rapide »| Symptôme | Première action | Commande |
|---|---|---|
CrashLoopBackOff avec RESTARTS élevés | Lire les logs précédents | kubectl logs <pod> --previous |
| Exit code 137, pas de logs | Vérifier la mémoire | kubectl describe pod <pod> → chercher OOMKilled |
| Exit code 127 | Vérifier l’image et la commande | kubectl describe pod <pod> → section Containers |
Events Unhealthy + Killing | La probe tue le conteneur | Revoir livenessProbe dans le manifeste |
Init:CrashLoopBackOff | L’init container crashe | kubectl logs <pod> -c <init-container> --previous |
| Logs montrent “connection refused” | Dépendance externe absente | Vérifier le Service/Endpoint cible |
À retenir
Section intitulée « À retenir »CrashLoopBackOffn’est pas une phase du Pod — c’est un état d’attente entre deux redémarrages, avec un délai qui double à chaque crash (10 s → 300 s max)kubectl logs --previousest votre commande principale : elle affiche les logs de l’exécution qui a plantékubectl describe podrévèle l’exit code, les événements et la configuration — indispensable quand les logs sont vides- Exit code 137 = processus tué par
SIGKILL, souvent un OOMKill (mais pas exclusivement) — vérifiez aveckubectl describe podpuis augmentezresources.limits.memorysi c’est confirmé - Exit code 127 = le binaire n’existe pas dans l’image — vérifiez la commande et le tag de l’image
- Si les events montrent
Unhealthy→Killing, c’est la liveness probe qui tue le conteneur, pas un crash applicatif - Après correction, surveillez le pod avec
kubectl get pods -wet vérifiez que les RESTARTS ne reprennent pas