Docker Debugging laufender Container: exec, inspect, stats, top, events
AI generated
Docker · Debugging · Troubleshooting · DevOps
Docker Debugging laufender Container
exec, inspect, stats, top, events und nsenter erklärt

Produktionsprobleme in Docker-Containern erfordern präzises Werkzeug, nicht Raten. Mit exec, inspect, stats, top und events lassen sich Prozesse, Konfiguration, Speicher und Ereignisse eines laufenden Containers vollständig untersuchen – ohne Neustart, ohne Datenverlust.

14 Min. Lesezeit exec · inspect · stats · top · events · cp · nsenter Docker 24+ · Linux · Produktion & Entwicklung

1. Systematisches Docker Debugging: der richtige Ansatz

Docker Debugging beginnt nicht mit dem Öffnen einer Shell im Container, sondern mit dem Verstehen des Problems aus der Vogelperspektive. Bevor man mit docker exec interaktiv in einen Container einsteigt, lohnt es sich, die Frage zu klären: Ist das Problem ein Prozessfehler, ein Ressourcenengpass, ein Konfigurationsproblem oder ein Netzwerkproblem? Je nach Antwort ist ein anderes Werkzeug das erste Mittel der Wahl. Ein systematischer Ansatz spart Zeit und vermeidet die Falle, lange mit einer offenen Shell zu suchen, obwohl docker inspect die Antwort in Sekunden geliefert hätte.

Der typische Ablauf beim Docker Debugging in der Produktion: Zuerst docker ps -a, um den aktuellen Status aller Container zu sehen. Dann docker stats --no-stream für einen Ressourcen-Snapshot. Dann docker logs --tail 100 für die letzten Ausgaben. Erst wenn diese drei Schritte kein klares Bild liefern, kommt docker inspect für die vollständige Konfigurationsanalyse oder docker exec für die direkte Untersuchung im laufenden Container. Diese Reihenfolge vermeidet blinde Aktionismus und reduziert die mittlere Zeit bis zur Problemlösung erheblich.

2. docker exec: Befehle im laufenden Container ausführen

docker exec ist das wichtigste Docker Debugging-Werkzeug für die direkte Untersuchung eines laufenden Containers. Es startet einen neuen Prozess im Namespace des Containers, ohne den bestehenden Hauptprozess zu unterbrechen. Mit -it öffnet man eine interaktive Shell, mit -u root kann man mit erhöhten Rechten arbeiten, auch wenn der Container-Prozess als normaler User läuft. Der Unterschied zu docker run ist fundamental: exec betritt einen laufenden Container, run startet einen neuen. Für Docker Debugging ist fast immer exec die richtige Wahl.

Häufig installierter Fallstrick: der Container basiert auf einem Distroless-Image oder Alpine ohne Shell. In diesem Fall schlägt docker exec -it container sh fehl. Die Lösung für Docker Debugging in solchen Containern ist nsenter auf Host-Ebene (dazu in Abschnitt 8) oder ein temporäres Debug-Image, das mit docker run --pid=container:target denselben Prozess-Namespace teilt. Seit Docker 24 gibt es außerdem docker debug, das automatisch ein Debug-Toolbox-Image in den Container-Namespace einbindet.


# Open an interactive shell in a running container (bash or sh fallback)
docker exec -it my-app bash 2>/dev/null || docker exec -it my-app sh

# Run a single diagnostic command non-interactively
docker exec my-app cat /etc/resolv.conf
docker exec my-app env | sort
docker exec my-app ps aux

# Execute as root even if container runs as non-root user
docker exec -u root -it my-app bash

# Check open network connections inside the container
docker exec my-app ss -tlnp
docker exec my-app cat /proc/net/tcp

# Inspect the filesystem — find recently modified files
docker exec my-app find /app -newer /tmp -type f -ls 2>/dev/null | head -20

# Docker 24+: debug distroless containers with built-in toolbox
docker debug my-app

3. docker inspect: vollständige Container-Konfiguration lesen

docker inspect liefert die vollständige JSON-Repräsentation eines laufenden oder gestoppten Containers: Netzwerkkonfiguration, Volume-Mounts, Umgebungsvariablen, Ressourcenlimits, Health-Check-Status, Labels, den Restart-Counter und den genauen Beendigungsgrund. Für Docker Debugging ist besonders der State-Block relevant: Er enthält ExitCode, Error, OOMKilled (ein Boolean, der anzeigt, ob der Container durch den OOM-Killer beendet wurde), StartedAt und FinishedAt. Mit --format lässt sich gezielt nur der relevante Teil extrahieren.

Die Go-Template-Syntax von --format ermöglicht präzise Abfragen ohne jq. Für das Docker Debugging besonders nützlich: docker inspect --format '{ {json .NetworkSettings.Networks} }' zeigt alle IP-Adressen und Netzwerke, { {range .Mounts} }{ {.Source} } → { {.Destination} }{ {println} }{ {end} } listet alle Volume-Mounts auf, und { {.State.OOMKilled} } prüft direkt, ob der letzte Crash ein OOM-Kill war. Kombiniert mit python3 -m json.tool lässt sich das vollständige JSON auch lesbar formatieren.

4. docker stats: Ressourcenverbrauch in Echtzeit

docker stats zeigt kontinuierlich aktualisierte Metriken für laufende Container: CPU-Prozentsatz bezogen auf alle verfügbaren Kerne, RAM-Nutzung im Verhältnis zum konfigurierten Limit, Netzwerk-I/O seit dem Container-Start und Block-I/O. Für Docker Debugging ist der Parameter --no-stream wichtig: Er gibt einen einmaligen Snapshot aus, ideal für Scripting und Snapshots. Mit --format lassen sich die Spalten anpassen. Der CPU-Prozentsatz bezieht sich auf alle Cores zusammen – ein Wert von 200% bedeutet also, dass der Container zwei volle Kerne auslastet.

Eine häufige Debugging-Situation: ein Container konsumiert konstant 100% CPU, ohne sichtbaren Grund. docker stats bestätigt die CPU-Auslastung, docker top zeigt welcher Prozess verantwortlich ist, und docker exec container cat /proc/PID/cmdline liefert die vollständige Befehlszeile. Die Kombination dieser drei Schritte führt beim Docker Debugging meist direkt zur Ursache – sei es ein Endless-Loop im Anwendungscode, ein Cronjob, der hängt, oder ein unkontrollierter Import-Prozess.


# One-shot resource snapshot for all running containers
docker stats --no-stream --format \
  "table { {.Name} }\t{ {.CPUPerc} }\t{ {.MemUsage} }\t{ {.MemPerc} }\t{ {.NetIO} }\t{ {.BlockIO} }"

# Inspect the full container state — check for OOM kill, exit code, restart count
docker inspect --format '
Name:         { {.Name} }
Exit Code:    { {.State.ExitCode} }
OOM Killed:   { {.State.OOMKilled} }
Restarts:     { {.RestartCount} }
Started:      { {.State.StartedAt} }
Finished:     { {.State.FinishedAt} }
Health:       { {.State.Health.Status} }
' my-app

# List all volume mounts
docker inspect --format \
  '{ {range .Mounts} }{ {.Type} } { {.Source} } → { {.Destination} } ({ {.Mode} }){ {println} }{ {end} }' my-app

# Show all environment variables (useful for configuration debugging)
docker inspect --format '{ {range .Config.Env} }{ {println .} }{ {end} }' my-app | sort

5. docker top: Prozesse im Container anzeigen

docker top zeigt alle laufenden Prozesse innerhalb eines Containers aus Sicht des Hosts – technisch gesehen liest es /proc des Hosts und filtert nach der Prozessgruppe des Containers. Das bedeutet, dass es auch für Container ohne installiertes ps funktioniert. Für Docker Debugging ist das essenziell, wenn der Container auf einem minimalen Image basiert. Standardmäßig zeigt docker top container die Spalten PID, UID, STATUS und CMD. Mit einem optionalen ps-Format-String (nach dem Container-Namen) kann man beliebige Spalten anfordern.

Besonders beim Docker Debugging von PHP-FPM-Containern ist docker top wertvoll: Man sieht sofort, wie viele Worker-Prozesse aktiv sind, ob sie im Status S (sleeping, warten auf Request) oder R (running, aktiv beschäftigt) sind, und ob Zombie-Prozesse (Z) angehäuft haben. Zombie-Prozesse entstehen, wenn der Elternprozess Exit-Codes seiner Kindprozesse nicht einsammelt. In Docker passiert das häufig, wenn der Container-Prozess kein korrektes PID-1-Verhalten implementiert.

6. docker events: Ereignisstrom des Docker-Daemons

docker events zeigt einen kontinuierlichen Strom aller Ereignisse, die der Docker-Daemon für Container, Images, Networks und Volumes erzeugt. Für Docker Debugging in der Produktion ist das besonders relevant, um zu verstehen, warum ein Container sich unerwartet neugestartet hat, wann genau ein Health-Check gescheitert ist oder wann ein Netzwerk neu verbunden wurde. Ohne docker events sind solche Ereignisse oft nur aus den Daemon-Logs rekonstruierbar.

Mit --filter lässt sich der Ereignisstrom auf relevante Typen eingrenzen. docker events --filter type=container --filter event=die --filter event=oom zeigt nur Container-Tode und OOM-Events. Mit --since und --until kann man vergangene Ereignisse abfragen – praktisch, wenn ein Fehler aufgetreten ist, bevor man mit dem Docker Debugging begonnen hat. docker events --format '{ {json .} }' gibt maschinenlesbares JSON aus, das sich in Skripte integrieren lässt.


# Stream all container events in real time
docker events --filter type=container

# Filter only crash and OOM events since last hour
docker events \
  --filter type=container \
  --filter event=die \
  --filter event=oom \
  --since "1h"

# Show processes inside container — works even without ps installed
docker top my-app
# With custom ps format: show PID, PPID, state, CPU, and full command
docker top my-app -eo pid,ppid,stat,pcpu,args

# Detect zombie processes (state Z = defunct)
docker top my-app -eo pid,ppid,stat,args | grep " Z "

# Fetch logs with timestamps, limit to last 50 lines, follow
docker logs --timestamps --tail 50 --follow my-app

# Copy a file out of the container for analysis (no exec needed)
docker cp my-app:/var/log/app/error.log ./container-error.log

7. docker logs: Ausgaben und Zeitstempel auswerten

docker logs liest die gepufferten Ausgaben des Container-Hauptprozesses aus dem Docker-Daemon. Für Docker Debugging ist der Parameter --timestamps unverzichtbar, weil er den genauen Zeitpunkt jeder Ausgabezeile zeigt. Mit --since und --until lässt sich der Zeitraum eingrenzen, --tail N beschränkt auf die letzten N Zeilen. Wichtig zu wissen: docker logs funktioniert nur, wenn der Logging-Driver json-file oder journald ist. Mit dem syslog- oder gelf-Driver werden Logs nicht lokal gespeichert und docker logs gibt eine Fehlermeldung zurück.

Ein häufiges Problem beim Docker Debugging mit Logs: der Container-Prozess schreibt nicht nach stdout/stderr, sondern in Dateien. In diesem Fall liefert docker logs keine relevanten Informationen. Mit docker exec container tail -f /var/log/app/error.log kann man trotzdem auf diese Logs zugreifen, oder man kopiert sie mit docker cp container:/var/log/app/error.log ./ auf den Host. Der Befehl docker cp funktioniert auch für gestoppte Container und ist daher beim Post-Mortem-Docker Debugging besonders wertvoll.

8. nsenter: Host-seitig in Container-Namespaces eintreten

nsenter ist das Werkzeug der letzten Instanz beim Docker Debugging: Es betritt die Linux-Namespaces eines Prozesses vom Host aus, ohne Docker zu benötigen. Das ist besonders nützlich, wenn der Docker-Daemon selbst hängt, wenn der Container keinen Shell-Interpreter hat, oder wenn man auf das Netzwerk-Namespace eines Containers mit Host-Tools wie tcpdump oder strace zugreifen will. Die PID des Container-Hauptprozesses findet man mit docker inspect --format '{ {.State.Pid} }'.

Mit nsenter --target PID --net ip addr kann man die Netzwerkkonfiguration des Containers mit dem Host-ip-Befehl abfragen – ideal, wenn der Container kein ip oder ifconfig installiert hat. Mit --mount --pid --net --ipc --uts betritt man alle Namespaces und hat effektiv eine Shell im Container-Kontext, aber mit dem Tool-Set des Hosts. Das ist beim Docker Debugging auf minimalistischen Produktions-Images die eleganteste Lösung.


# Get the host PID of the container's main process
CONTAINER_PID=$(docker inspect --format '{ {.State.Pid} }' my-app)
echo "Container PID on host: $CONTAINER_PID"

# Enter the container's network namespace with host tools
# Useful for tcpdump, ss, ip — even if container has no shell
nsenter --target "$CONTAINER_PID" --net -- ip addr
nsenter --target "$CONTAINER_PID" --net -- ss -tlnp
nsenter --target "$CONTAINER_PID" --net -- tcpdump -i eth0 -c 100 -w /tmp/capture.pcap

# Enter all namespaces — effectively a shell in container context with host tools
nsenter --target "$CONTAINER_PID" --mount --pid --net --ipc --uts -- bash

# Attach strace to a specific process inside the container
WORKER_PID=$(docker exec my-app cat /var/run/php-fpm.pid)
nsenter --target "$CONTAINER_PID" --pid -- strace -p "$WORKER_PID" -e trace=network,file

# Inspect /proc filesystem for memory maps and open files
ls -la /proc/"$CONTAINER_PID"/fd | wc -l        # number of open file descriptors
cat /proc/"$CONTAINER_PID"/status | grep VmRSS   # actual resident memory

9. Diagnose-Werkzeuge im Vergleich

Die verschiedenen Docker Debugging-Werkzeuge haben unterschiedliche Stärken und Einsatzbereiche. Die Wahl des richtigen Werkzeugs für die jeweilige Frage reduziert die Diagnosezeit erheblich.

Werkzeug Beste Frage Einschränkung Container muss laufen?
docker exec Was ist im Filesystem / Environment? Braucht Shell im Image Ja
docker inspect Wie ist der Container konfiguriert? Kein Liveblick ins Filesystem Nein (auch gestoppt)
docker stats Wie viel Ressourcen verbraucht er? Kein historischer Verlauf Ja
docker top Welche Prozesse laufen? Keine Netzwerkinfo Ja
docker events Was ist wann passiert? Nur Docker-Daemon-Events Nein (historisch)

In der Praxis ist die effizienteste Docker Debugging-Sequenz: docker inspect für den schnellen Konfigurationscheck, dann docker stats und docker top für Ressourcen und Prozesse, dann docker logs für Ausgaben, und erst als letzten Schritt docker exec für die interaktive Untersuchung. Wer diese Reihenfolge kennt und einhält, verschwendet keine Zeit mit einer offenen Shell, wenn die Antwort bereits in inspect oder stats sichtbar wäre.

Mironsoft

Docker-Diagnose, Container-Troubleshooting und Produktions-Debugging

Container-Probleme in der Produktion schnell lösen?

Wir analysieren auffällige Container-Stacks, identifizieren Memory-Leaks, CPU-Spitzen und Konfigurationsfehler mit den richtigen Werkzeugen – ohne unnötige Neustarts, ohne Datenverlust.

Live-Diagnose

exec, inspect, stats und nsenter für die Analyse laufender Produktions-Container

Post-Mortem

Analyse von OOM-Events, Exit-Codes und Events-Historien nach Container-Abstürzen

Debugging-Playbooks

Dokumentierte Diagnose-Abläufe für euer Team, damit das nächste Problem schneller gelöst wird

10. Zusammenfassung

Systematisches Docker Debugging laufender Container folgt einem klaren Werkzeug-Auswahlprinzip: docker inspect für Konfiguration und Status, docker stats für Ressourcenverbrauch, docker top für Prozesse, docker logs für Ausgaben, docker events für den zeitlichen Verlauf von Daemon-Ereignissen und docker exec für die direkte Untersuchung im Container-Filesystem. Jedes dieser Werkzeuge beantwortet eine andere Frage und ist in einer anderen Phase der Fehlersuche am wertvollsten. Das effizienteste Docker Debugging beginnt außen und arbeitet sich nach innen vor.

Für Container ohne Shell oder auf minimalistischen Images ist nsenter der Weg, Host-Tools wie tcpdump, strace oder ip im Namespace des Containers anzuwenden. Seit Docker 24 vereinfacht docker debug diesen Prozess durch eine eingebaute Debug-Toolbox. Die Kombination aus docker events mit Zeitfilter und docker inspect .State.OOMKilled ermöglicht Post-Mortem-Analysen, die auch nach einem Container-Neustart noch relevante Informationen liefern.

Docker Debugging — Das Wichtigste auf einen Blick

Erster Blick

docker ps -a + docker stats --no-stream + docker logs --tail 100 — reicht oft für die Diagnose, bevor exec nötig wird.

Konfiguration & Status

docker inspect --format '{ {.State.OOMKilled} }' — schnellste Prüfung auf OOM-Kill, auch bei gestoppten Containern.

Shell-lose Container

nsenter --target PID --net nutzt Host-Tools im Container-Namespace. docker debug (Docker 24+) für Distroless-Images.

Ereignis-Historie

docker events --filter event=die --since 1h zeigt vergangene Container-Abstürze mit genauem Zeitstempel.

11. FAQ: Docker Debugging laufender Container

1Erster Schritt beim Debugging eines auffälligen Containers?
docker ps -a → docker stats --no-stream → docker logs --tail 100. Erst danach inspect oder exec, wenn die Ursache noch unklar ist.
2Container ohne Shell debuggen?
nsenter --target PID --net -- bash nutzt Host-Tools im Container-Namespace. docker debug (Docker 24+) für Distroless-Images.
3OOM-Kill erkennen?
Exit-Code 137 + docker inspect --format '{ {.State.OOMKilled} }' gibt true zurück. Kernel-Bestätigung: dmesg | grep oom.
4Warum gibt docker logs nichts aus?
Logging-Driver ist nicht json-file/journald, oder Prozess schreibt in Dateien statt stdout. docker inspect zeigt den Driver.
5docker top vs. ps ax?
docker top liest /proc des Hosts, filtert nach Container-Prozessgruppe. Funktioniert ohne ps im Container-Image.
6docker events nach Zeitraum filtern?
--since 2h oder --since '2026-05-09T10:00:00'. Mit --filter event=die nur Container-Abstürze anzeigen.
7docker cp auf gestoppten Container?
Ja. docker cp funktioniert auch auf gestoppte Container. Ideal für Post-Mortem-Analysen: Logs und Configs kopieren ohne Neustart.
8CPU-Monopolisten im Container finden?
docker stats bestätigt Auslastung, docker top container -eo pid,pcpu,args zeigt verursachende Prozesse.
9Zombie-Prozesse in Docker?
Entstehen wenn PID 1 Exit-Codes von Kindprozessen nicht einsammelt. Lösung: tini oder dumb-init als Init-Prozess.
10docker exec vs. docker run beim Debugging?
exec betritt den laufenden Container (Zustand erhalten), run startet einen neuen. Für Problemdiagnose im laufenden System immer exec.