Ein falsches Kommando kann deinen Container beenden
docker exec und docker attach wirken auf den ersten Blick austauschbar, beide verschaffen Zugriff auf einen laufenden Container. Technisch handelt es sich jedoch um zwei grundverschiedene Mechanismen. Wer den Unterschied nicht kennt, riskiert im produktiven Betrieb, den Hauptprozess versehentlich zu beenden, nur weil ein Terminal geschlossen wurde.
Inhaltsverzeichnis
- 1. Zwei Wege in einen laufenden Container
- 2. Wie docker exec technisch funktioniert
- 3. Wie docker attach an den Hauptprozess andockt
- 4. Warum attach den Container beenden kann
- 5. Das PID-1-Problem im Container
- 6. Mehrere parallele Sitzungen mit exec
- 7. Wann attach tatsächlich die richtige Wahl ist
- 8. Best Practices für den produktiven Einsatz
- 9. Entscheidungshilfe: exec oder attach?
- 10. Zusammenfassung
- 11. FAQ
1. Zwei Wege in einen laufenden Container
Ein Container ist im Kern nichts anderes als ein isolierter Linux-Prozessbaum. Der Prozess, der beim Start mit ENTRYPOINT oder CMD ausgeführt wird, bekommt innerhalb des Containers die Prozess-ID 1 zugewiesen. Alles, was ein Entwickler danach zusätzlich in diesem Container erledigen möchte, muss sich entweder an genau diesen einen Prozess anhängen oder einen komplett neuen Prozess daneben starten. Genau das ist der Unterschied zwischen docker attach und docker exec, und er ist keine stilistische Feinheit, sondern betrifft die Prozessverwaltung des Kernels direkt.
docker exec erzeugt über die Namespace-APIs des Kernels einen völlig neuen Prozess innerhalb der Namespaces des Containers, ohne den ursprünglichen Hauptprozess zu berühren. docker attach hingegen öffnet lediglich die bestehenden Standard-Ein- und Ausgabeströme von PID 1 erneut und leitet sie an das aktuelle Terminal um. Es wird kein zusätzlicher Prozess erzeugt, sondern eine bereits existierende Verbindung wiederhergestellt. Diese Unterscheidung erklärt fast alle Überraschungen, die Einsteiger mit beiden Kommandos erleben.
2. Wie docker exec technisch funktioniert
Beim Aufruf von docker exec weist der Docker-Daemon den Container-Runtime (containerd bzw. runc) an, einen neuen Prozess in denselben Namespaces zu starten, in denen bereits PID 1 läuft: gleicher Netzwerk-Namespace, gleiches Dateisystem, gleiche Cgroup-Beschränkungen. Der neue Prozess bekommt dabei intern eine eigene, höhere PID, bleibt aber vollständig unabhängig vom Hauptprozess. Schließt man das Terminal oder beendet die Shell mit exit, stirbt nur dieser Nebenprozess, der Hauptprozess läuft unbeeindruckt weiter.
Das macht exec zum Standardwerkzeug für Debugging, Wartungsarbeiten und Health-Checks. Man kann beliebig viele parallele exec-Sitzungen öffnen, ohne den laufenden Betrieb zu stören. Wichtig ist dabei, dass der ausgeführte Befehl im Container tatsächlich existiert, andernfalls schlägt der Aufruf mit einem klaren Fehler fehl, ohne irgendeine Auswirkung auf PID 1 zu haben.
# Neue interaktive Shell im laufenden Container öffnen
docker exec -it webshop_app /bin/bash
# Einzelbefehl ausführen, ohne interaktive Shell
docker exec webshop_app php bin/magento cache:status
# Prozessliste zeigt zwei unabhängige PIDs
docker exec webshop_app ps aux
# PID USER COMMAND
# 1 root php-fpm: master process
# 47 root bash
3. Wie docker attach an den Hauptprozess andockt
docker attach erzeugt keinen neuen Prozess, sondern verbindet das lokale Terminal direkt mit den Standard-Streams (stdin, stdout, stderr) von PID 1. Das ist genau der Mechanismus, den auch docker run ohne die Option -d intern nutzt, um die Ausgabe eines Containers live im Vordergrund anzuzeigen. Wer attach nutzt, sieht also exakt das, was der Hauptprozess selbst ausgibt, nicht mehr und nicht weniger.
Das ist bei einem Datenbankserver oder einem Webserver im Vordergrundmodus durchaus sinnvoll, etwa um Live-Logausgaben direkt am Prozess zu beobachten, ohne einen separaten Logging-Treiber zu konfigurieren. Problematisch wird es jedoch, sobald man versucht, mit dem Hauptprozess zu interagieren, ohne die Konsequenzen der Terminal-Kopplung zu verstehen.
# An den Hauptprozess des Containers andocken
docker attach webshop_db
# Verbindung ohne Signalweiterleitung trennen (empfohlen)
# Tastenkombination im Terminal: Strg+P gefolgt von Strg+Q
4. Warum attach den Container beenden kann
Der häufigste Fehler entsteht, wenn eine Entwicklerin oder ein Entwickler nach einer attach-Sitzung die Sitzung mit der gewohnten Tastenkombination Strg+C verlassen möchte. Da das Terminal direkt mit stdin von PID 1 verbunden ist, wird dieses Signal standardmäßig genau an diesen Prozess weitergereicht, nicht nur an die Terminal-Sitzung. Ein Webserver oder eine Datenbank interpretiert SIGINT in aller Regel als Aufforderung, sich sauber zu beenden, und der gesamte Container stoppt.
Der korrekte Weg, eine attach-Sitzung zu verlassen, ohne den Container zu beeinflussen, ist die Tastenkombination Strg+P gefolgt von Strg+Q, das sogenannte Detach-Sequence. Alternativ kann man die Signalweiterleitung beim Aufruf komplett deaktivieren, was insbesondere in Wartungsfenstern empfehlenswert ist, wenn Unsicherheit über das Verhalten des Ziel-Prozesses besteht.
# Signale werden NICHT an PID 1 weitergeleitet
docker attach --sig-proxy=false webshop_db
# Zum Vergleich: Strg+C in einer normalen attach-Sitzung
# schickt SIGINT an PID 1 und kann den Container stoppen
5. Das PID-1-Problem im Container
In einem klassischen Linux-System übernimmt init oder systemd als PID 1 besondere Aufgaben: verwaiste Kindprozesse einsammeln (Reaping) und Signale sinnvoll weiterleiten. Viele Anwendungen wie ein einfaches Node.js- oder PHP-Skript sind für diese Rolle nicht ausgelegt und ignorieren Standardsignale oder reagieren unerwartet darauf, wenn sie direkt als PID 1 im Container laufen. Das verschärft die Risiken von docker attach zusätzlich, weil das Verhalten je nach Anwendung stark variiert.
Aus diesem Grund empfiehlt es sich, produktive Container mit einem minimalen Init-System wie tini zu starten, das als PID 1 fungiert und Signale korrekt an den eigentlichen Anwendungsprozess weiterreicht. Docker bietet dafür seit Version 1.13 die eingebaute Option --init, die genau dieses Verhalten ohne zusätzliches Image-Layer bereitstellt.
# Container mit eingebautem Init-Prozess starten
docker run --init -d --name webshop_app mironsoft/webshop:latest
# PID 1 ist jetzt tini, nicht die Anwendung selbst
docker exec webshop_app ps -o pid,comm
6. Mehrere parallele Sitzungen mit exec
Ein praktischer Vorteil von docker exec, den attach prinzipbedingt nicht bietet, ist die Möglichkeit, beliebig viele unabhängige Sitzungen gleichzeitig zu öffnen. Ein Entwickler kann in einem Terminal die Logdatei einer Anwendung live verfolgen, während in einem zweiten Terminal parallel Datenbankabfragen getestet und in einem dritten der Speicherverbrauch beobachtet wird, ganz ohne dass sich die Sitzungen gegenseitig stören.
Das ist besonders bei komplexen Debugging-Situationen wertvoll, etwa wenn ein Fehler nur unter Last reproduzierbar ist. Ein Terminal erzeugt künstliche Last mit einem Benchmark-Tool, ein zweites beobachtet parallel die Prozessliste und ein drittes prüft Logdateien. Bei attach wäre das nicht möglich, da immer nur eine Verbindung zu den Streams von PID 1 gleichzeitig bestehen kann.
# Terminal 1: Live-Logs verfolgen
docker exec webshop_app tail -f var/log/system.log
# Terminal 2: Datenbankabfrage testen
docker exec -it webshop_db mysql -u root -p webshop
# Terminal 3: Ressourcenverbrauch live beobachten
docker exec webshop_app top
7. Wann attach tatsächlich die richtige Wahl ist
Trotz aller Risiken hat attach durchaus berechtigte Einsatzgebiete. Wenn ein Container bewusst im Vordergrund mit docker run gestartet und die Ausgabe versehentlich vom Terminal getrennt wurde, etwa weil die SSH-Sitzung abgebrochen ist, erlaubt attach, wieder Sichtkontakt zur Live-Ausgabe herzustellen, ohne den Prozess neu zu starten. Auch bei interaktiven Programmen, die direkt als PID 1 laufen und auf Tastatureingaben über stdin warten, ist attach oft der einzige Weg, tatsächlich mit dem Prozess zu interagieren.
Ein weiteres legitimes Szenario ist das gezielte Testen von Signalverhalten selbst, etwa um zu verifizieren, ob eine Anwendung SIGTERM korrekt für einen sauberen Shutdown verarbeitet, bevor sie produktiv eingesetzt wird. In diesem Fall ist die Signalweiterleitung von attach kein Nachteil, sondern genau die gewünschte Eigenschaft, um das reale Verhalten beim Beenden zu überprüfen.
8. Best Practices für den produktiven Einsatz
Für den alltäglichen Debugging- und Wartungsbetrieb sollte docker exec die Standardwahl sein, weil es keine Auswirkung auf den Hauptprozess hat und beliebig oft wiederholt werden kann. Zusätzlich lohnt es sich, exec-Sitzungen mit expliziten Nutzern und Umgebungsvariablen zu versehen, um Berechtigungsprobleme zu vermeiden und reproduzierbare Debugging-Umgebungen zu schaffen, statt sich auf den Root-Standardnutzer des Containers zu verlassen.
Sollte attach dennoch nötig sein, gehört die Detach-Sequenz Strg+P Strg+Q ins Standardrepertoire jedes Teams, ebenso wie das Wissen um --sig-proxy=false für riskante Situationen. Teams, die regelmäßig mit attach arbeiten, profitieren außerdem davon, produktive Container grundsätzlich mit --init zu starten, damit Signale kontrolliert verarbeitet werden, statt den Container ungewollt zu beenden.
# exec mit explizitem Nutzer und Umgebungsvariable
docker exec -it -u www-data -e APP_ENV=dev webshop_app bash
# Root-Rechte nur wenn wirklich noetig
docker exec -it -u root webshop_app bash
9. Entscheidungshilfe: exec oder attach?
In der Praxis lässt sich die Entscheidung fast immer anhand einer einzigen Frage treffen: Will ich etwas zusätzlich im Container tun, ohne den Hauptprozess zu beeinflussen, oder will ich die tatsächliche Ein- und Ausgabe von PID 1 selbst sehen und steuern? Im ersten Fall ist exec praktisch immer die richtige Wahl, im zweiten Fall bleibt attach das einzige passende Werkzeug.
Die folgende Tabelle fasst typische Situationen aus dem Alltag zusammen und ordnet ihnen das jeweils passende Kommando zu, inklusive einer kurzen Einschätzung des Risikos bei falscher Handhabung.
| Situation | Empfohlenes Kommando | Begründung | Risiko bei Fehlbedienung |
|---|---|---|---|
| Shell zum Debuggen öffnen | docker exec -it |
Neuer, unabhängiger Prozess | Keines, unabhängig von PID 1 |
| Health-Check per Skript | docker exec |
Automatisierbar, kein TTY nötig | Keines |
| Live-Ausgabe eines Vordergrundprozesses ansehen | docker attach |
Direkter Zugriff auf stdout von PID 1 | Strg+C kann Container stoppen |
| Interaktive Eingabe an PID 1 senden | docker attach |
Einziger Weg für Interaktion mit dem Hauptprozess | Falsche Tastenkombination beendet Prozess |
| Mehrere Debugging-Sitzungen parallel | docker exec |
Beliebig oft wiederholbar | Keines |
| Signalverhalten der Anwendung testen | docker attach |
Signale werden real an PID 1 gesendet | Gewollter Effekt, kein Risiko |
Mironsoft
Container-Infrastruktur, CI-Pipelines und Deployment-Automatisierung
Docker-Setups, die im Team und in Produktion tragfähig bleiben?
Wir prüfen bestehende Dockerfiles und Compose-Stacks auf Sicherheitslücken, aufgeblähte Images und fragile Build-Pipelines und bauen daraus eine Container-Infrastruktur, die schnell baut, sicher läuft und im Team nachvollziehbar bleibt.
Dockerfile-Review
Multi-Stage-Builds, Layer-Caching und Image-Größe systematisch optimieren.
Security-Audit
Container-Isolation, Secrets-Handling und Image-Scanning gegen echte Angriffsflächen absichern.
CI/CD-Integration
Build-Pipelines, Registries und Deployment-Strategien für reproduzierbare Releases aufbauen.
10. Zusammenfassung
docker exec vs. attach: Das Wichtigste auf einen Blick
exec
Startet einen neuen, unabhängigen Prozess im Container, ohne PID 1 zu berühren.
attach
Verbindet das Terminal direkt mit den Streams von PID 1, inklusive Signalweiterleitung.
Risiko
Strg+C in einer attach-Sitzung kann den gesamten Container beenden.
Empfehlung
Für Debugging und Wartung standardmäßig exec verwenden, attach gezielt und mit Detach-Sequenz.