Aller au contenu
Conteneurs & Orchestration medium

Diagnostiquer avec kubectl get, describe, logs et top

26 min de lecture

logo kubernetes

Quatre commandes suffisent pour diagnostiquer 90 % des problèmes Kubernetes : kubectl get repère les ressources en erreur, kubectl describe explique pourquoi, kubectl logs montre ce que l’application a écrit, et kubectl top détecte les goulets de ressources. Ce guide vous apprend à les combiner efficacement.

À la fin de ce guide, vous saurez :

  • Lister et filtrer des ressources avec kubectl get (labels, colonnes personnalisées, formats de sortie)
  • Inspecter l’état complet d’un pod avec kubectl describe et interpréter chaque section de sa sortie
  • Extraire les logs d’un conteneur (en temps réel, multi-conteneurs, après un crash)
  • Surveiller CPU et mémoire avec kubectl top et repérer les fuites de ressources
  • Diagnostiquer les 6 incidents les plus courants grâce aux runbooks en fin de guide

kubectl get est votre point d’entrée. Il affiche l’état de n’importe quelle ressource Kubernetes : pods, services, deployments, nodes, etc.

Fenêtre de terminal
kubectl get <ressource> [nom] [-n namespace] [options]

Exemples courants :

Fenêtre de terminal
# Tous les pods du namespace courant
kubectl get pods
# Tous les pods de tous les namespaces
kubectl get pods -A
# Un pod précis
kubectl get pod mon-pod
# Plusieurs types de ressources en une commande
kubectl get pods,services,deployments

Les labels permettent de cibler précisément les ressources qui vous intéressent :

Fenêtre de terminal
# Pods avec un label précis
kubectl get pods -l app=nginx
# Combiner plusieurs labels (ET logique)
kubectl get pods -l app=nginx,env=production
# Exclure un label
kubectl get pods -l 'app!=nginx'
# Label présent (quelle que soit la valeur)
kubectl get pods -l 'app'

Par défaut, kubectl get affiche un tableau lisible. Vous pouvez changer le format selon vos besoins :

OptionUsageExemple
-o wideColonnes supplémentaires (IP, node)kubectl get pods -o wide
-o yamlManifeste YAML completkubectl get pod mon-pod -o yaml
-o jsonFormat JSON (pour scripts)kubectl get pods -o json
-o nameNoms uniquementkubectl get pods -o name
-o jsonpathExtraction cibléekubectl get pod mon-pod -o jsonpath='{.status.phase}'
-o custom-columnsTableau personnaliséVoir ci-dessous

Pour construire un affichage sur mesure :

Fenêtre de terminal
kubectl get pods -o custom-columns=\
NOM:.metadata.name,\
STATUS:.status.phase,\
IP:.status.podIP,\
NODE:.spec.nodeName

Résultat :

NOM STATUS IP NODE
nginx-abc123 Running 10.244.1.5 worker-1
redis-def456 Pending <none> <none>

JSONPath permet d’extraire exactement l’information dont vous avez besoin :

Fenêtre de terminal
# IP d'un pod
kubectl get pod mon-pod -o jsonpath='{.status.podIP}'
# Image utilisée par le premier conteneur
kubectl get pod mon-pod -o jsonpath='{.spec.containers[0].image}'
# Toutes les images de tous les pods
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'

L’option --watch (-w) actualise l’affichage à chaque changement d’état :

Fenêtre de terminal
kubectl get pods -w

C’est particulièrement utile après un déploiement ou pendant un incident pour voir les transitions d’état (Pending → ContainerCreating → Running ou → Error).

BesoinCommande
Vue rapidekubectl get pods
Tous les namespaceskubectl get pods -A
Avec IP et nodekubectl get pods -o wide
Filtrer par labelkubectl get pods -l app=nginx
Format scriptkubectl get pods -o json
Valeur précisekubectl get pod X -o jsonpath='{.status.phase}'
Temps réelkubectl get pods -w

Quand kubectl get montre un pod en erreur, kubectl describe vous dit pourquoi. Il affiche la configuration complète et les événements récents.

Fenêtre de terminal
kubectl describe <ressource> <nom> [-n namespace]
Fenêtre de terminal
# Décrire un pod
kubectl describe pod mon-pod
# Décrire un node
kubectl describe node worker-1
# Décrire un service
kubectl describe service mon-service

La sortie est longue. Voici comment la lire efficacement, section par section :

kubectl describe pod mon-pod (sortie annotée)
Name: mon-pod ← Identité
Namespace: default
Node: worker-1/192.168.1.10 ← Sur quel node il tourne
Status: Running ← État global
IP: 10.244.1.5 ← IP du pod
Containers: ← Configuration des conteneurs
nginx:
Image: nginx:1.25 ← Image utilisée
Port: 80/TCP
State: Running ← État du conteneur
Started: Mon, 01 Jan 2026 10:00:00
Ready: True
Restart Count: 0 ← 0 = stable, >0 = problème potentiel
Limits: ← Ressources maximales autorisées
cpu: 500m
memory: 128Mi
Requests: ← Ressources demandées au scheduler
cpu: 250m
memory: 64Mi
Conditions: ← Check-list de santé
Type Status
Initialized True ← Init containers OK
Ready True ← Prêt à recevoir du trafic
ContainersReady True ← Tous les conteneurs sont prêts
PodScheduled True ← Planifié sur un node
Events: ← SECTION LA PLUS IMPORTANTE
Type Reason Age Message
---- ------ --- -------
Normal Scheduled 2m Successfully assigned default/mon-pod to worker-1
Normal Pulled 2m Container image "nginx:1.25" already present
Normal Created 2m Created container nginx
Normal Started 2m Started container nginx

describe fonctionne sur toutes les ressources Kubernetes. En particulier :

RessourceCe que describe révèle
nodeCapacité, allocations, conditions (MemoryPressure, DiskPressure), pods hébergés
serviceEndpoints (pods ciblés), sélecteur de labels, ports
deploymentStratégie de rollout, replicas, conditions, événements de scaling
pvcStorageClass, taille, status (Bound/Pending), volume associé
Fenêtre de terminal
# Un node manque de ressources ?
kubectl describe node worker-1 | grep -A5 "Allocated resources"
# Un service ne route pas le trafic ?
kubectl describe service mon-service | grep -A5 "Endpoints"

Une fois le pod identifié et son état compris, kubectl logs vous montre ce que l’application a écrit sur stdout/stderr.

Fenêtre de terminal
kubectl logs <pod> [-n namespace] [options]
OptionEffetExemple
-fFlux continu (comme tail -f)kubectl logs -f mon-pod
--tail=NN dernières ligneskubectl logs --tail=50 mon-pod
--since=TLogs depuis une duréekubectl logs --since=5m mon-pod
--timestampsAjouter l’horodatagekubectl logs --timestamps mon-pod
-c conteneurConteneur spécifique (multi-conteneur)kubectl logs mon-pod -c sidecar
-pConteneur précédent (après crash)kubectl logs -p mon-pod
--all-containersTous les conteneurs du podkubectl logs --all-containers mon-pod
Fenêtre de terminal
kubectl logs --tail=100 mon-pod | grep -i "error\|fatal\|panic\|exception"
Fenêtre de terminal
kubectl logs --since=10m mon-pod --timestamps
Fenêtre de terminal
kubectl logs -p mon-pod

4. Logs d’un conteneur spécifique (sidecar/init)

Section intitulée « 4. Logs d’un conteneur spécifique (sidecar/init) »
Fenêtre de terminal
# Lister les conteneurs d'un pod
kubectl get pod mon-pod -o jsonpath='{.spec.containers[*].name}'
# Voir les logs du sidecar
kubectl logs mon-pod -c istio-proxy
Fenêtre de terminal
kubectl logs -l app=nginx --all-containers --tail=50

Pour suivre les logs de plusieurs pods simultanément, stern est l’outil idéal :

Fenêtre de terminal
# Installer stern
brew install stern # macOS
# ou
go install github.com/stern/stern@latest
# Suivre tous les pods nginx
stern nginx
# Avec filtre sur le contenu
stern nginx --include "error"
Message dans les logsSignification probableAction
connection refusedService cible inactif ou mauvais portVérifier le service cible avec describe svc
permission deniedRBAC ou filesystemVérifier le ServiceAccount et les montages
OOMKilledDépassement de limite mémoireAugmenter resources.limits.memory
no such hostDNS ne résout pasVérifier le nom de service et CoreDNS
dial tcp: i/o timeoutRéseau bloquéVérifier NetworkPolicies et connectivité
certificate signed by unknown authorityTLS mal configuréVérifier les secrets TLS et la CA

kubectl top affiche la consommation CPU et mémoire en temps réel des nodes et des pods.

Fenêtre de terminal
kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
worker-1 350m 17% 2048Mi 52%
worker-2 820m 41% 3200Mi 82%
control 150m 7% 1024Mi 26%

Surveillez les nodes avec un usage CPU > 80 % ou mémoire > 85 % — ils sont proches de la saturation et peuvent causer des évictions de pods.

Fenêtre de terminal
# Tous les pods du namespace
kubectl top pods
# Un pod précis
kubectl top pod mon-pod
# Tous les namespaces, triés par CPU
kubectl top pods -A --sort-by=cpu
# Avec détail par conteneur
kubectl top pod mon-pod --containers
NAME CPU(cores) MEMORY(bytes)
nginx-abc123 5m 32Mi
redis-def456 120m 256Mi
api-server-xyz 450m 512Mi

Pour repérer un conteneur dont la consommation mémoire croît sans cesse :

Fenêtre de terminal
# Surveiller toutes les 10 secondes
watch -n 10 kubectl top pod mon-pod --containers

Si la colonne MEMORY augmente régulièrement sans retomber, c’est probablement une fuite mémoire. Comparez avec la limite définie :

Fenêtre de terminal
kubectl get pod mon-pod -o jsonpath='{.spec.containers[0].resources.limits.memory}'

Quand la consommation atteint la limite, Kubernetes tue le conteneur avec le status OOMKilled.

Voici l’enchaînement complet pour diagnostiquer un pod en erreur :

  1. Repérer le pod en erreur

    Fenêtre de terminal
    kubectl get pods -A | grep -v Running | grep -v Completed

    Cette commande affiche uniquement les pods dont l’état n’est pas normal.

  2. Comprendre la cause

    Fenêtre de terminal
    kubectl describe pod <nom-du-pod> -n <namespace>

    Scrollez directement jusqu’à la section Events. Cherchez les lignes Warning.

  3. Lire les logs applicatifs

    Fenêtre de terminal
    # Si le pod tourne encore
    kubectl logs <nom-du-pod> --tail=100
    # Si le pod a crashé
    kubectl logs -p <nom-du-pod>
  4. Vérifier les ressources

    Fenêtre de terminal
    kubectl top pod <nom-du-pod>
    kubectl top node

    Comparez la consommation avec les limits définies dans le manifeste.

  5. Investiguer plus en profondeur si nécessaire

    Si le problème persiste, passez à l’investigation avancée avec kubectl exec et debug.

Ces runbooks couvrent les 6 incidents les plus fréquents en production. Pour chaque incident : symptôme, diagnostic pas à pas, et résolution.

Symptôme : kubectl get pods affiche Status = Pending depuis plus de 30 secondes.

Causes fréquentes : ressources insuffisantes sur les nodes, affinité/anti-affinité non satisfaite, PVC non lié.

  1. Lire les événements du pod

    Fenêtre de terminal
    kubectl describe pod <nom> -n <namespace> | grep -A20 "Events:"

    Cherchez FailedScheduling dans les événements.

  2. Identifier la cause dans le message

    Message EventsCauseSolution
    Insufficient cpuPas assez de CPU disponibleAjoutez un node ou réduisez les requests
    Insufficient memoryPas assez de mémoire disponibleAjoutez un node ou réduisez les requests
    node(s) had taintTaint sans tolerationAjoutez la toleration au pod ou retirez le taint
    node(s) didn't match Pod's node affinityAffinité non satisfaiteVérifiez nodeSelector ou nodeAffinity
    persistentvolumeclaim not foundPVC inexistantCréez le PVC ou corrigez le nom
  3. Vérifier la capacité des nodes

    Fenêtre de terminal
    kubectl describe nodes | grep -A5 "Allocated resources"

    Comparez Requests et Limits avec la capacité totale.

  4. Vérifier les PVC si applicable

    Fenêtre de terminal
    kubectl get pvc -n <namespace>

    Un PVC en Pending signifie qu’aucun PV ne correspond (taille, storageClass, mode d’accès).

  5. Résoudre

    Fenêtre de terminal
    # Option A : libérer des ressources
    kubectl top pods -A --sort-by=cpu | head -10
    # Option B : vérifier les taints
    kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
    # Option C : forcer le scheduling (si drain actif)
    kubectl uncordon <node>

Symptôme : kubectl get pods affiche Status = CrashLoopBackOff, le RESTARTS augmente.

Causes fréquentes : erreur applicative au démarrage, variable d’environnement manquante, point de montage incorrect, commande de démarrage invalide.

  1. Voir les logs de l’exécution qui a crashé

    Fenêtre de terminal
    kubectl logs -p <nom> -n <namespace>

    C’est la commande la plus importante. Elle montre les logs du conteneur avant qu’il ne soit tué.

  2. Examiner la configuration du pod

    Fenêtre de terminal
    kubectl describe pod <nom> -n <namespace>

    Vérifiez dans la sortie :

    • Last State : Terminated avec le Reason (Error, OOMKilled)
    • Exit Code : 1 = erreur applicative, 137 = OOMKilled, 139 = segfault
    • Restart Count : combien de fois le conteneur a redémarré
  3. Vérifier les variables d’environnement et volumes

    Fenêtre de terminal
    # Variables d'environnement injectées
    kubectl get pod <nom> -o jsonpath='{.spec.containers[0].env[*].name}'
    # ConfigMaps référencés
    kubectl get pod <nom> -o jsonpath='{.spec.containers[0].envFrom[*].configMapRef.name}'
    # Secrets référencés
    kubectl get pod <nom> -o jsonpath='{.spec.containers[0].envFrom[*].secretRef.name}'

    Si un ConfigMap ou Secret n’existe pas, le pod crashe au démarrage.

  4. Tester l’image manuellement

    Fenêtre de terminal
    kubectl run debug-test --image=<image> --rm -it -- sh

    Si l’image ne démarre pas non plus en mode interactif, le problème est dans l’image elle-même.

  5. Résoudre selon l’exit code

    Exit CodeSignificationAction
    0Succès (le process se termine normalement)Vérifiez que la commande est un process long, pas un script one-shot
    1Erreur applicativeLisez les logs -p, corrigez le code ou la config
    126Permission deniedVérifiez les permissions de l’entrypoint
    127Commande introuvableVérifiez command: dans le manifeste
    137OOMKilled (SIGKILL)Augmentez limits.memory
    139Segfault (SIGSEGV)Bug dans l’application, problème d’architecture (arm64/amd64)

Symptôme : kubectl get pods affiche Status = ImagePullBackOff ou ErrImagePull.

Causes fréquentes : image inexistante, tag incorrect, registre privé sans credentials, limite de rate Docker Hub.

  1. Identifier l’image en cause

    Fenêtre de terminal
    kubectl describe pod <nom> -n <namespace> | grep -i "image\|pull\|back"
  2. Vérifier que l’image existe

    Fenêtre de terminal
    # Tester le pull depuis votre machine
    docker pull <image:tag>
    # Ou avec crane (sans Docker)
    crane manifest <image:tag>
  3. Vérifier les credentials du registre

    Fenêtre de terminal
    # ImagePullSecrets configurés sur le pod ?
    kubectl get pod <nom> -o jsonpath='{.spec.imagePullSecrets[*].name}'
    # Le secret existe ?
    kubectl get secret <nom-secret> -n <namespace>
    # Contenu du secret (base64)
    kubectl get secret <nom-secret> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
  4. Vérifier le ServiceAccount par défaut

    Fenêtre de terminal
    kubectl get serviceaccount default -n <namespace> -o yaml | grep -A5 imagePullSecrets
  5. Résoudre

    Fenêtre de terminal
    # Créer un secret pour un registre privé
    kubectl create secret docker-registry regcred \
    --docker-server=registry.example.com \
    --docker-username=user \
    --docker-password=pass \
    -n <namespace>
    # Attacher au ServiceAccount par défaut
    kubectl patch serviceaccount default -n <namespace> \
    -p '{"imagePullSecrets": [{"name": "regcred"}]}'

Runbook 4 — Service inaccessible (pas de réponse)

Section intitulée « Runbook 4 — Service inaccessible (pas de réponse) »

Symptôme : un curl ou une requête HTTP vers un Service Kubernetes ne répond pas ou retourne connection refused.

  1. Vérifier que le Service a des endpoints

    Fenêtre de terminal
    kubectl get endpoints <service> -n <namespace>

    Si la colonne ENDPOINTS est vide (<none>), aucun pod ne correspond au sélecteur du Service.

  2. Comparer le sélecteur du Service avec les labels des pods

    Fenêtre de terminal
    # Sélecteur du Service
    kubectl get svc <service> -n <namespace> -o jsonpath='{.spec.selector}'
    # Pods avec ces labels
    kubectl get pods -n <namespace> -l <key>=<value>

    Si aucun pod ne matche, il y a une incohérence entre les labels.

  3. Vérifier que les pods ciblés sont Ready

    Fenêtre de terminal
    kubectl get pods -n <namespace> -l <key>=<value> -o wide

    Un pod qui n’est pas Ready est retiré des endpoints du Service.

  4. Tester la connectivité depuis le cluster

    Fenêtre de terminal
    kubectl run test-net --image=busybox --rm -it -- wget -qO- http://<service>.<namespace>.svc.cluster.local:<port>
  5. Vérifier les NetworkPolicies

    Fenêtre de terminal
    kubectl get networkpolicies -n <namespace>

    Une NetworkPolicy peut bloquer le trafic entrant vers les pods.

  6. Résoudre

    • Labels incohérents → corriger les labels du Deployment ou le sélecteur du Service
    • Pod pas Ready → vérifier les readinessProbes (kubectl describe pod)
    • NetworkPolicy → ajuster les règles d’ingress

    Pour plus de détails sur les Services et le port-forward : kubectl expose, port-forward et proxy.

Symptôme : le pod redémarre avec Reason: OOMKilled (visible dans kubectl describe pod) ou Exit Code 137.

  1. Confirmer l’OOMKilled

    Fenêtre de terminal
    kubectl describe pod <nom> -n <namespace> | grep -A3 "Last State"

    Vous devez voir Reason: OOMKilled.

  2. Mesurer la consommation réelle

    Fenêtre de terminal
    kubectl top pod <nom> --containers

    Comparez avec la limite définie :

    Fenêtre de terminal
    kubectl get pod <nom> -o jsonpath='{range .spec.containers[*]}{.name}: {.resources.limits.memory}{"\n"}{end}'
  3. Analyser l’historique de consommation

    Si vous avez Prometheus/Grafana, consultez la métrique container_memory_working_set_bytes. Sinon, surveillez avec watch :

    Fenêtre de terminal
    watch -n 5 kubectl top pod <nom> --containers

    Une croissance linéaire sans palier indique une fuite mémoire.

  4. Résoudre

    SituationAction
    Pic ponctuel au démarrageAugmentez limits.memory de 20-30 %
    Croissance continue (fuite)Corrigez l’application (profiling mémoire)
    Limite trop basse par rapport au besoin réelAjustez requests et limits
    Fenêtre de terminal
    # Modifier la limite mémoire (via le Deployment)
    kubectl set resources deployment <nom> \
    --limits=memory=512Mi \
    --requests=memory=256Mi

Symptôme : kubectl get pods affiche Status = Evicted. Les pods évincés restent visibles mais ne tournent plus.

  1. Identifier la raison de l’éviction

    Fenêtre de terminal
    kubectl describe pod <nom-evicted> -n <namespace> | grep -i "message\|reason\|status"

    Les raisons courantes : The node was low on resource: ephemeral-storage ou memory.

  2. Vérifier la pression sur le node

    Fenêtre de terminal
    kubectl describe node <node> | grep -A5 "Conditions"

    Cherchez MemoryPressure, DiskPressure ou PIDPressure à True.

  3. Identifier les consommateurs principaux

    Fenêtre de terminal
    # CPU et mémoire par pod sur ce node
    kubectl top pods -A --field-selector spec.nodeName=<node> --sort-by=memory
    # Espace disque éphémère (si applicable)
    kubectl get pods -A --field-selector spec.nodeName=<node> \
    -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'
  4. Nettoyer les pods évincés

    Les pods évincés ne servent plus à rien, supprimez-les :

    Fenêtre de terminal
    kubectl get pods -A --field-selector status.phase=Failed | grep Evicted
    kubectl delete pods -A --field-selector status.phase=Failed
  5. Prévenir les futures évictions

    • Ajoutez des requests et limits sur tous les pods
    • Configurez des PodDisruptionBudgets pour les workloads critiques
    • Surveillez l’espace disque avec kubectl top et des alertes Prometheus
    • Envisagez le drain contrôlé pour la maintenance
Status / ErreurCommande de diagnosticCause la plus fréquente
Pendingkubectl describe pod → EventsRessources insuffisantes ou taint
CrashLoopBackOffkubectl logs -pErreur applicative au démarrage
ImagePullBackOffkubectl describe pod → EventsImage inexistante ou credentials manquants
OOMKilledkubectl describe pod → Last StateLimite mémoire trop basse
Evictedkubectl describe pod + describe nodeNode en pression (disque/mémoire)
CreateContainerErrorkubectl describe pod → EventsConfigMap/Secret manquant
RunContainerErrorkubectl describe pod → EventsCommande de démarrage invalide
Service sans réponsekubectl get endpointsPas de pods matchant le sélecteur
  • kubectl get liste et filtre les ressources — commencez toujours par là pour repérer les anomalies.
  • kubectl describe inspecte une ressource en détail — allez directement à la section Events.
  • kubectl logs affiche les journaux applicatifs — utilisez -p pour voir les logs d’un conteneur crashé.
  • kubectl top montre la consommation CPU/mémoire en temps réel — nécessite metrics-server.
  • Le pipeline get → describe → logs → top couvre 90 % des diagnostics Kubernetes.
  • Les 6 runbooks en fin de guide traitent les incidents les plus courants avec des commandes copier-coller.

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.