Veröffentlicht am

Kubernetes Troubleshooting: Systematisch debuggen

Teilen:
Authors

Kubernetes Troubleshooting: Systematisch debuggen

TL;DR

Kubernetes-Debugging folgt einem klaren Muster: Pod-Status pruefen, Events lesen, Logs analysieren, Container inspizieren. Die meisten Probleme fallen in wenige Kategorien -- ImagePullBackOff, CrashLoopBackOff, Pending Pods, Service-Routing und DNS. Wer die richtige Reihenfolge kennt und die passenden kubectl-Befehle beherrscht, loest 90% aller Cluster-Probleme in Minuten statt Stunden.


Der Debugging-Flow: Vom Pod zum Node

Kubernetes-Probleme lassen sich systematisch eingrenzen. Statt wahllos Logs zu durchsuchen, arbeitet man sich von innen nach aussen vor:

PodContainerServiceIngressNodeCluster

Jede Ebene hat eigene Symptome und eigene Diagnose-Tools. Der erste Schritt ist immer gleich:

# Ueberblick verschaffen: Was laeuft, was nicht?
kubectl get pods -A --field-selector=status.phase!=Running

# Detaillierte Pod-Info mit Events
kubectl describe pod <pod-name> -n <namespace>

# Logs des aktuellen Containers
kubectl logs <pod-name> -n <namespace>

# Logs des vorherigen (abgestuerzten) Containers
kubectl logs <pod-name> -n <namespace> --previous

Die Events-Sektion in kubectl describe ist Gold wert. Sie zeigt chronologisch, was der Scheduler, Kubelet und Controller-Manager mit dem Pod gemacht haben.

ImagePullBackOff und ErrImagePull

Der Pod kann das Container-Image nicht herunterladen. Haeufigste Ursachen: falscher Image-Name, fehlende Registry-Credentials oder Netzwerkprobleme.

# Events pruefen -- zeigt die genaue Fehlermeldung
kubectl describe pod <pod-name> | grep -A 5 "Events:"

# Typische Ausgabe:
# Failed to pull image "myregistry.io/app:v2.1":
# rpc error: code = Unknown desc = Error response from daemon:
# manifest for myregistry.io/app:v2.1 not found

# ImagePullSecret pruefen
kubectl get pod <pod-name> -o jsonpath='{.spec.imagePullSecrets[*].name}'

# Secret existiert und ist korrekt?
kubectl get secret <secret-name> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d

Checkliste fuer ImagePullBackOff:

  1. Image-Name und Tag korrekt geschrieben?
  2. Image existiert in der Registry? (lokal mit docker pull testen)
  3. ImagePullSecret im Pod-Spec referenziert?
  4. Secret im richtigen Namespace?
  5. Registry-Credentials noch gueltig (Token abgelaufen)?

CrashLoopBackOff

Der Container startet, stuerzt ab, wird neu gestartet -- in einer Endlosschleife. Das Restart-Intervall steigt exponentiell (10s, 20s, 40s, bis 5min).

# Restart-Counter und Status pruefen
kubectl get pod <pod-name> -o wide

# Logs des abgestuerzten Containers anzeigen
kubectl logs <pod-name> --previous

# Exit-Code des letzten Container-Starts
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}'
Exit-CodeBedeutungTypische Ursache
0Normales EndeProzess beendet sich sofort (fehlende CMD)
1Allgemeiner FehlerAnwendungsfehler, fehlende Config
127Command not foundFalsches Entrypoint/CMD im Dockerfile
137SIGKILL (OOMKilled)Memory Limit zu niedrig
139SIGSEGVSegmentation Fault in der Anwendung
143SIGTERMGraceful Shutdown (normal bei Rolling Updates)

Bei Exit-Code 137 (OOMKilled) hilft:

# OOMKilled bestaetigen
kubectl describe pod <pod-name> | grep -i oom

# Aktuellen Memory-Verbrauch pruefen
kubectl top pod <pod-name>

# Memory Limit erhoehen
kubectl set resources deployment/<name> --limits=memory=512Mi

Pending Pods

Der Pod bleibt im Status Pending haengen -- der Scheduler findet keinen passenden Node.

# Warum ist der Pod Pending?
kubectl describe pod <pod-name> | grep -A 10 "Events:"

# Typische Meldungen:
# "0/3 nodes are available: 3 Insufficient cpu"
# "0/3 nodes are available: 3 node(s) had taint ... that the pod didn't tolerate"
# "persistentvolumeclaim ... not found"

# Verfuegbare Ressourcen auf allen Nodes pruefen
kubectl describe nodes | grep -A 5 "Allocated resources"

# Node-Taints anzeigen
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

Die drei haeufigsten Gruende fuer Pending Pods:

  1. Ressourcen-Engpass: CPU oder Memory Requests uebersteigen die verfuegbare Kapazitaet. Loesung: Requests reduzieren, Nodes skalieren oder Cluster Autoscaler konfigurieren.

  2. Taints und Tolerations: Nodes haben Taints, die der Pod nicht toleriert. Oft bei Control-Plane-Nodes oder spezialisierten GPU-Nodes.

  3. PVC nicht gebunden: Ein PersistentVolumeClaim findet kein passendes PersistentVolume. StorageClass pruefen und sicherstellen, dass der Provisioner funktioniert.

Service-Debugging: Kein Traffic kommt an

Der Pod laeuft, aber der Service leitet keinen Traffic weiter. Das Problem liegt fast immer bei den Label-Selektoren.

# Service-Selector anzeigen
kubectl get svc <service-name> -o jsonpath='{.spec.selector}'

# Endpoints pruefen: Sind Pods zugeordnet?
kubectl get endpoints <service-name>

# Leere Endpoints = Selector stimmt nicht mit Pod-Labels ueberein
# Pod-Labels pruefen
kubectl get pods --show-labels | grep <app-name>

# Manueller Test: Vom Cluster aus den Pod direkt ansprechen
kubectl run debug-curl --rm -it --image=curlimages/curl -- \
  curl -v http://<pod-ip>:<container-port>/health

Wenn Endpoints vorhanden sind aber der Traffic trotzdem nicht ankommt, liegt es oft an der targetPort-Konfiguration. Der targetPort im Service muss mit dem Port uebereinstimmen, auf dem der Container tatsaechlich lauscht.

DNS-Probleme diagnostizieren

DNS ist das Rueckgrat der Service-Kommunikation in Kubernetes. Wenn DNS nicht funktioniert, funktioniert fast nichts.

# DNS-Pod-Status pruefen
kubectl get pods -n kube-system -l k8s-app=kube-dns

# DNS-Aufloesung aus einem Debug-Pod testen
kubectl run dns-test --rm -it --image=busybox:1.36 -- nslookup kubernetes.default

# Detaillierter DNS-Test mit dig
kubectl run dns-debug --rm -it --image=tutum/dnsutils -- \
  dig +short my-service.default.svc.cluster.local

# CoreDNS-Logs pruefen
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

Haeufige DNS-Probleme:

  • CoreDNS-Pods nicht ready: Neustart mit kubectl rollout restart deployment/coredns -n kube-system
  • Falsche resolv.conf im Pod: kubectl exec <pod> -- cat /etc/resolv.conf pruefen
  • NDOTS-Konfiguration: Standard ist ndots:5, was bei externen Domains zu unnoetig vielen DNS-Queries fuehrt

kubectl debug: Ephemeral Containers

Seit Kubernetes 1.25 stabil. Ephemeral Containers ermoeglichen Debugging direkt im laufenden Pod -- auch wenn das Original-Image keine Shell hat (z.B. Distroless).

# Debug-Container an laufenden Pod anhaengen
kubectl debug -it <pod-name> --image=busybox:1.36 --target=<container-name>

# Debug-Container mit Netzwerk-Tools
kubectl debug -it <pod-name> --image=nicolaka/netshoot --target=<container-name>

# Im Debug-Container: Netzwerk pruefen
ip addr
ss -tlnp
curl -v http://localhost:8080/health
tcpdump -i eth0 port 8080 -c 20

# Node-Level Debugging
kubectl debug node/<node-name> -it --image=ubuntu

Mit --target teilt der Debug-Container den Process-Namespace mit dem Ziel-Container. So sind die Prozesse des Original-Containers sichtbar, auch wenn dessen Image kein ps hat.

Entscheidungsbaum: Schnelle Diagnose

Pod startet nicht?
├── Status: ImagePullBackOffImage-Name, Registry-Credentials pruefen
├── Status: CrashLoopBackOffLogs mit --previous lesen, Exit-Code pruefen
├── Status: Pending → describe pod → Resources, Taints, PVC pruefen
├── Status: Running aber nicht Ready
│   └── Readiness Probe schlaegt fehl → Probe-Config und Anwendungs-Health pruefen
└── Status: Running und Ready, aber kein Traffic
    ├── Service: Endpoints leer → Label-Selector pruefen
    ├── Service: Endpoints vorhanden → targetPort pruefen
    ├── Ingress: 404/502Ingress-Controller Logs und Service-Referenz pruefen
    └── DNS: Aufloesung schlaegt fehl → CoreDNS-Status und resolv.conf pruefen

Dieser Baum deckt 90% der taeglichen Kubernetes-Probleme ab.

FAQ

Wie finde ich heraus, warum ein Pod neugestartet wurde?

kubectl describe pod <pod-name> zeigt in der Sektion Last State den Grund und Exit-Code des letzten Container-Stops. Bei OOMKill steht dort Reason: OOMKilled. Fuer detaillierte Logs des abgestuerzten Containers: kubectl logs <pod-name> --previous.

Was ist der Unterschied zwischen kubectl debug und kubectl exec?

kubectl exec fuehrt Befehle im laufenden Container aus -- setzt aber voraus, dass der Container eine Shell hat. kubectl debug startet einen neuen Ephemeral Container mit eigenem Image (z.B. mit Netzwerk-Tools) und kann den Process-Namespace des Ziel-Containers teilen. Ideal fuer Distroless Images.

Wie debugge ich Netzwerk-Probleme zwischen zwei Pods?

Zuerst pruefen, ob NetworkPolicies den Traffic blockieren: kubectl get networkpolicies -A. Dann mit einem Debug-Pod (nicolaka/netshoot) aus dem Quell-Namespace den Ziel-Pod direkt per IP ansprechen. Funktioniert das, liegt das Problem beim Service oder DNS. Funktioniert es nicht, blockiert eine NetworkPolicy oder ein CNI-Problem den Traffic.

Mein Pod ist Running aber nicht Ready -- was tun?

Die Readiness Probe schlaegt fehl. kubectl describe pod zeigt die genaue Probe-Konfiguration und die Fehlermeldung. Haeufige Ursachen: falscher Probe-Pfad, falscher Port, Anwendung braucht laenger zum Starten als initialDelaySeconds erlaubt. Probe-Parameter anpassen oder den Health-Endpoint der Anwendung pruefen.

Wie kann ich alle fehlerhaften Pods im Cluster auf einmal finden?

kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded zeigt alle Pods, die nicht im erwarteten Zustand sind. Fuer mehr Detail: kubectl get events -A --sort-by='.lastTimestamp' --field-selector type=Warning listet alle Warnings chronologisch auf.


Kubernetes ohne DevOps-Overhead?

Wir betreiben Ihre Kubernetes-Cluster 24/7 – Sie fokussieren auf Ihr Kerngeschäft. Ab 4.000€/Monat, DSGVO-konform, mit deutschem Support.

24/7 SupportDeutsche RechenzentrenDSGVO-konform

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen