Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Diagnostiquer un CrashLoopBackOff Kubernetes

14 min de lecture

logo kubernetes

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.

  • 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 --previous et kubectl describe pod pour trouver la cause réelle
  • Reproduire et corriger un CrashLoopBackOff sur un cluster de test
  • Un cluster Kubernetes fonctionnel (v1.28+)
  • kubectl configuré et connecté au cluster
  • Des droits de lecture sur les pods, événements et logs
  • Connaissances de base sur les Pods et les probes

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.

Quand un conteneur plante, le kubelet applique un délai croissant avant chaque nouveau redémarrage :

TentativeDélai avant redémarrageTemps total écoulé
1re10 secondes10 s
2e20 secondes30 s
3e40 secondes1 min 10 s
4e80 secondes2 min 30 s
5e160 secondes5 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é.

Voici les causes les plus fréquentes rencontrées en pratique :

#CauseSymptôme typiqueOù chercher
1Erreur applicativeException, panic, segfault dans les logskubectl logs
2Configuration manquanteVariable d’env absente, fichier de config introuvablekubectl describe pod (env, volumes)
3OOMKilledLe conteneur dépasse sa limite mémoirekubectl describe podLast State: OOMKilled
4Probe mal configurée (liveness ou startup)Unhealthy, Killing, redémarrages répétéskubectl describe pod → Events, définition des probes
5Commande ou entrypoint invalideLe conteneur s’arrête immédiatement avec exit code 126 ou 127kubectl describe pod, kubectl logs --previous
6Dépendance externe indisponibleLa base de données ou l’API n’est pas accessiblekubectl logs (timeout, connection refused)
  1. Identifier le pod en CrashLoopBackOff

    Listez les pods et repérez ceux dont le STATUS est CrashLoopBackOff ou dont le compteur RESTARTS augmente :

    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.

  2. 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> --previous

    Si le pod contient plusieurs conteneurs, précisez le conteneur :

    Fenêtre de terminal
    kubectl logs <pod> -n <namespace> -c <conteneur> --previous

    Cherchez des indices : Exception, Error, panic, Traceback, connection refused, OOM, permission denied.

  3. 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 ?
  4. Corriger et vérifier

    Selon la cause identifiée :

    CauseAction corrective
    Erreur applicativeCorriger le code ou la config, redéployer
    Config manquanteAjouter le ConfigMap/Secret, vérifier les noms
    OOMKilledAugmenter resources.limits.memory
    Probe mal configuréeAugmenter initialDelaySeconds, timeoutSeconds, ou ajouter une startup probe
    Commande/entrypoint invalideVérifier command: et args: dans le manifeste
    Dépendance externeVé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> -w

    Le flag -w (watch) permet de suivre l’évolution en temps réel. Le pod doit passer à Running et le compteur de RESTARTS ne doit plus augmenter.

Pour bien comprendre le mécanisme, créons volontairement un pod qui crashe.

apiVersion: v1
kind: Pod
metadata:
name: crash-exit-error
namespace: default
spec:
restartPolicy: Always
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "echo 'Application démarrée'; sleep 2; echo 'Erreur fatale!'; exit 1"]
Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: crash-exit-error
namespace: default
spec:
restartPolicy: Always
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "echo 'Application démarrée'; sleep 2; echo 'Erreur fatale!'; exit 1"]
EOF

Attendez 30 secondes puis observez :

Fenêtre de terminal
kubectl get pods crash-exit-error -w

Vous verrez le STATUS passer de Running à Error puis à CrashLoopBackOff, avec le compteur RESTARTS qui augmente.

Diagnostic :

Fenêtre de terminal
# Logs de l'exécution qui a crashé
kubectl logs crash-exit-error --previous
# Description avec exit code
kubectl describe pod crash-exit-error | grep -A5 "Last State"

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 :

Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: crash-oom
namespace: default
spec:
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"
EOF

Le 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 :

Fenêtre de terminal
kubectl describe pod crash-oom | grep -A5 "Last State"

Vous verrez Reason: OOMKilled et Exit Code: 137.

Fenêtre de terminal
kubectl delete pod crash-exit-error crash-oom --force --grace-period=0

Les exit codes aident à identifier rapidement la nature du crash :

Exit codeSignificationCause probable
0Arrêt normalLe conteneur s’est terminé volontairement — si restartPolicy: Always, il sera relancé
1Erreur génériqueBug applicatif, exception non gérée
2Mauvais usage de commande shellCommande ou argument invalide dans command:
126Permission deniedLe binaire n’est pas exécutable
127Command not foundLe binaire n’existe pas dans l’image
137SIGKILL (128 + 9)Processus tué par SIGKILL — souvent un OOMKill, mais pas exclusivement
139SIGSEGV (128 + 11)Segmentation fault dans l’application
143SIGTERM (128 + 15)Arrêt gracieux demandé par Kubernetes

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.

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: 503
Normal Killing 10s kubelet Container app failed liveness probe, will be restarted

La solution est de revoir la configuration de la probe :

  • Augmenter initialDelaySeconds si l’application met du temps à démarrer
  • Augmenter timeoutSeconds si 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.

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 :

Fenêtre de terminal
kubectl logs <pod> -c <init-container> --previous
SymptômePremière actionCommande
CrashLoopBackOff avec RESTARTS élevésLire les logs précédentskubectl logs <pod> --previous
Exit code 137, pas de logsVérifier la mémoirekubectl describe pod <pod> → chercher OOMKilled
Exit code 127Vérifier l’image et la commandekubectl describe pod <pod> → section Containers
Events Unhealthy + KillingLa probe tue le conteneurRevoir livenessProbe dans le manifeste
Init:CrashLoopBackOffL’init container crashekubectl logs <pod> -c <init-container> --previous
Logs montrent “connection refused”Dépendance externe absenteVérifier le Service/Endpoint cible
  • CrashLoopBackOff n’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 --previous est votre commande principale : elle affiche les logs de l’exécution qui a planté
  • kubectl describe pod ré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 avec kubectl describe pod puis augmentez resources.limits.memory si 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 UnhealthyKilling, c’est la liveness probe qui tue le conteneur, pas un crash applicatif
  • Après correction, surveillez le pod avec kubectl get pods -w et vérifiez que les RESTARTS ne reprennent pas

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn