und produktive Logging-Strategien
Wer Docker Logs nur mit docker logs liest, verliert im Produktionsbetrieb jeden Überblick. Strukturiertes Logging über stdout und stderr, der richtige Log-Treiber und ein zentrales Log-Management-System machen Container-Logs beobachtbar, durchsuchbar und alarmierbar.
Inhaltsverzeichnis
- 1. Das Grundprinzip: stdout und stderr in Docker
- 2. docker logs: Möglichkeiten und Grenzen
- 3. Log-Treiber: json-file, journald, syslog und mehr
- 4. Log-Rotation: Speicherverbrauch kontrollieren
- 5. Strukturiertes Logging: JSON-Format und Labels
- 6. Zentrales Logging mit Loki und Promtail
- 7. Fluentd und Fluent Bit als Log-Aggregatoren
- 8. Logging in Anwendungen korrekt konfigurieren
- 9. Log-Treiber im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Das Grundprinzip: stdout und stderr in Docker
Docker baut auf einem einfachen Konzept auf: Jeder Container soll seine Ausgaben ausschließlich nach stdout und stderr schreiben, statt direkt in Logdateien. Das ist keine willkürliche Konvention, sondern folgt dem Unix-Prinzip, dass ein Prozess nichts über seine Laufzeitumgebung wissen soll – er gibt aus, und die Infrastruktur entscheidet, was damit passiert. Docker fängt diese Streams ab und leitet sie an den konfigurierten Log-Treiber weiter. Der Docker-Daemon verwaltet die Docker Logs damit zentral, unabhängig davon, welche Anwendung im Container läuft.
Dieses Prinzip hat weitreichende Konsequenzen: Eine Anwendung, die in eine Datei innerhalb des Containers schreibt, erzeugt keine Docker Logs. Die Ausgaben sind nur über einen Bind-Mount oder Volume erreichbar, lassen sich nicht über docker logs abfragen und verschwinden beim Entfernen des Containers. Für produktionsreife Container-Infrastrukturen ist das Schreiben nach stdout und stderr deshalb nicht optional, sondern Pflicht. Wer bestehende Anwendungen containerisiert, muss oft prüfen, ob die Logging-Konfiguration entsprechend angepasst wurde – viele Frameworks schreiben standardmäßig in Dateien, nicht in die Standard-Streams.
Ein wichtiger technischer Aspekt: stdout und stderr werden intern als zwei separate Streams behandelt und in den Docker Logs mit dem Attribut stream: stdout bzw. stream: stderr gekennzeichnet. Mit dem Flag docker logs 2>/dev/null lässt sich stderr unterdrücken, mit docker logs 1>/dev/null stdout. Das ist nützlich beim Debuggen, wenn man nur Fehlermeldungen oder nur normale Ausgaben sehen möchte.
2. docker logs: Möglichkeiten und Grenzen
Der Befehl docker logs ist das naheliegendste Werkzeug für Docker Logs, hat aber in der Produktion deutliche Grenzen. Mit --follow lassen sich Logs in Echtzeit verfolgen, mit --since und --until ein Zeitfenster einschränken, mit --tail die letzten N Zeilen abrufen. Für einfache Diagnosen bei einem einzelnen Container reicht das. Sobald aber mehrere Container, mehrere Nodes oder ein Kubernetes-Cluster im Spiel sind, ist docker logs unzureichend: Es gibt keine übergreifende Suche, keine Aggregation, keine Persistenz über Container-Restarts hinaus.
Ein weiteres Problem: Standardmäßig speichert Docker Docker Logs als JSON-Dateien unter /var/lib/docker/containers/<ID>/<ID>-json.log. Ohne Rotation wächst diese Datei unbegrenzt. In Produktionsumgebungen mit vielen Containern kann das in kurzer Zeit den gesamten Speicherplatz des Hosts belegen. Dieses Problem ist dokumentiert und regelmäßig Ursache für Produktionsvorfälle – nicht weil Entwickler es nicht wissen, sondern weil es in der anfänglichen Infrastruktur-Konfiguration vergessen wurde.
# Basic log access commands
docker logs my-container
docker logs --follow --tail 100 my-container
# Time-based filtering
docker logs --since 2h my-container
docker logs --since "2026-05-09T08:00:00" --until "2026-05-09T09:00:00" my-container
# Separate stdout and stderr
docker logs my-container 2>/dev/null # stdout only
docker logs my-container 1>/dev/null # stderr only
# Find the raw JSON log file location
docker inspect --format='{ {.LogPath} }' my-container
# Check log file size on disk
docker inspect --format='{ {.LogPath} }' my-container | xargs wc -c
# Follow logs across multiple containers using docker compose
docker compose logs --follow --tail 50 web php
3. Log-Treiber: json-file, journald, syslog und mehr
Docker unterstützt verschiedene Log-Treiber, die bestimmen, wohin Docker Logs fließen. Der Standard-Treiber json-file schreibt alle Logs als JSON-Zeilen in Dateien auf dem Host. Das ist für Entwicklungsumgebungen praktisch, für die Produktion aber meistens die schlechteste Wahl, weil keine automatische Rotation, keine Weiterleitung und kein zentrales Management enthalten ist. Der Treiber journald leitet Docker Logs in das systemd-Journal weiter, was auf Linux-Hosts mit systemd eine konsistente Integration in die bestehende Log-Infrastruktur ermöglicht. journalctl -u docker-<container-id> liefert dann alle Container-Logs mit den üblichen Journal-Filtermöglichkeiten.
Für Teams, die ein zentrales Log-System betreiben, sind die Treiber gelf (Graylog Extended Log Format), fluentd und awslogs relevant. Diese leiten Docker Logs direkt an ein externes System weiter, ohne sie auf dem Host zu speichern. Das hat einen entscheidenden Nachteil: Ist das externe System nicht erreichbar, blockiert das Logging und der Container kann keine Ausgaben mehr schreiben – oder Logs gehen verloren, je nach Konfiguration. Für den Treiber local (ab Docker 20.10) gilt: Er speichert Logs in einem komprimierten Binärformat und rotiert automatisch, ist aber nicht über die Docker-API abfragbar.
4. Log-Rotation: Speicherverbrauch kontrollieren
Log-Rotation ist eine der kritischsten Konfigurationen für produktive Docker Logs. Ohne sie wachsen Log-Dateien unbegrenzt, bis der Host-Speicher voll ist und neue Prozesse keine Dateien mehr schreiben können. Das betrifft nicht nur die Anwendung selbst, sondern den gesamten Host inklusive aller anderen Container. Die Rotation lässt sich entweder global im Docker-Daemon konfigurieren oder pro Container in der Compose-Datei oder beim docker run-Aufruf.
Die empfohlene Konfiguration kombiniert eine maximale Dateigröße (max-size) mit einer maximalen Anzahl von Dateien (max-file). Mit max-size: 10m und max-file: 5 werden maximal 50 MB pro Container für Docker Logs reserviert. Docker rotiert die Datei automatisch, sobald sie die angegebene Größe erreicht. Wichtig: Die Rotation löscht die älteste Datei, wenn die maximale Anzahl überschritten wird. Bei der Kapazitätsplanung muss man also berechnen, wie viele Container gleichzeitig laufen und welches Gesamtvolumen an Logs entstehen kann.
# Global log rotation in /etc/docker/daemon.json
# Apply with: systemctl restart docker
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5",
"compress": "true"
}
}
# Per-container override in docker-compose.yml
services:
web:
image: nginx:alpine
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
compress: "true"
labels: "app,environment"
# Use 'local' driver for better compression (Docker 20.10+)
app:
image: myapp:latest
logging:
driver: "local"
options:
max-size: "20m"
max-file: "7"
# Check actual disk usage of Docker logs
du -sh /var/lib/docker/containers/*/
find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \;
5. Strukturiertes Logging: JSON-Format und Labels
Strukturierte Docker Logs im JSON-Format sind der entscheidende Unterschied zwischen Logs, die man lesen kann, und Logs, die man auswerten kann. Ein Plaintext-Log wie ERROR: Verbindung fehlgeschlagen muss mit regulären Ausdrücken geparst werden, um Felder wie Schweregrad, Zeitstempel und Kontext zu extrahieren. Ein strukturiertes Log in JSON enthält diese Felder direkt: {"level":"error","msg":"Verbindung fehlgeschlagen","service":"checkout","duration_ms":3200}. Log-Management-Systeme können dann direkt auf diese Felder filtern und aggregieren.
Docker-Container-Labels spielen dabei eine wichtige Rolle: Mit dem Log-Treiber-Option labels oder env werden Container-Labels oder Umgebungsvariablen automatisch zu jedem Log-Eintrag hinzugefügt. So erscheinen in jedem Log-Eintrag Metadaten wie app=checkout, environment=production oder version=2.4.1, ohne dass die Anwendung diese Informationen selbst kennen muss. Das ist besonders wertvoll, wenn mehrere Versionen einer Anwendung gleichzeitig laufen und Logs gezielt nach Version gefiltert werden sollen.
6. Zentrales Logging mit Loki und Promtail
Grafana Loki ist ein Log-Aggregations-System, das speziell für Container-Umgebungen entwickelt wurde und sich nahtlos in Grafana integriert. Im Gegensatz zu Elasticsearch speichert Loki nicht den gesamten Inhalt der Docker Logs, sondern nur Metadaten und komprimierte Log-Streams. Das macht es wesentlich ressourcenschonender und kosteneffizienter für Teams, die ihre Infrastruktur selbst betreiben. Promtail ist der zugehörige Agent, der auf jedem Docker-Host läuft und Docker Logs aus den JSON-Dateien liest, mit Labels anreichert und an Loki sendet.
Die Konfiguration eines Promtail-Agents für Docker ist überschaubar: Man gibt den Pfad zu den Docker-Log-Dateien an, definiert Labels auf Basis des Container-Namens und der Service-Metadaten und legt den Loki-Endpunkt fest. In Grafana können dann Log-Queries mit LogQL geschrieben werden, die nach Service, Severity oder beliebigen JSON-Feldern filtern. Die Integration mit Grafana-Dashboards ermöglicht es, Docker Logs direkt neben Metriken aus Prometheus anzuzeigen – zeitlich korreliert, was die Fehlersuche erheblich beschleunigt.
# docker-compose.yml: Loki + Promtail stack
services:
loki:
image: grafana/loki:3.0.0
ports:
- "3100:3100"
volumes:
- loki_data:/loki
- ./loki-config.yml:/etc/loki/local-config.yaml
command: -config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:3.0.0
volumes:
# Mount Docker socket to discover containers
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount log directory for reading
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
grafana:
image: grafana/grafana:10.4.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
volumes:
- grafana_data:/var/lib/grafana
volumes:
loki_data:
grafana_data:
# promtail-config.yml — scrape Docker log files
# scrape_configs:
# - job_name: docker
# docker_sd_configs:
# - host: unix:///var/run/docker.sock
# refresh_interval: 5s
7. Fluentd und Fluent Bit als Log-Aggregatoren
Fluentd und sein schlankes Pendant Fluent Bit sind die etabliertesten Log-Aggregatoren im CNCF-Ökosystem. Fluentd wird direkt als Docker-Log-Treiber unterstützt: Mit --log-driver=fluentd sendet Docker alle Docker Logs per TCP oder Unix-Socket an einen laufenden Fluentd-Prozess. Fluentd kann diese Logs dann filtern, transformieren, mit zusätzlichen Metadaten anreichern und an beliebige Ziele weiterleiten – Elasticsearch, S3, BigQuery oder ein anderes System. Die Flexibilität der Fluentd-Pipelines macht es möglich, denselben Log-Stream gleichzeitig an ein schnelles Echtzeit-System für Alerts und ein langfristiges Archiv für Compliance zu senden.
Fluent Bit ist die ressourcenschonendere Alternative für Umgebungen, in denen Speicher und CPU begrenzt sind – zum Beispiel auf Edge-Nodes oder in großen Kubernetes-Clustern mit Hunderten von Pods. Fluent Bit kann ebenfalls Docker Logs direkt aus den JSON-Dateien lesen und nach Loki, Elasticsearch oder Fluentd weiterleiten. Die Konfiguration ist einfacher als bei Fluentd, die Transformationsmöglichkeiten sind jedoch begrenzt. In der Praxis setzt man oft Fluent Bit als Agent auf jedem Node ein und Fluentd als zentralen Aggregator, der die komplexe Routing-Logik übernimmt.
8. Logging in Anwendungen korrekt konfigurieren
Die häufigste Fehlerquelle bei Docker Logs ist nicht die Docker-Konfiguration, sondern die Anwendung selbst. PHP-Anwendungen schreiben standardmäßig in /var/log/php/error.log, Nginx in /var/log/nginx/access.log und error.log, MySQL in /var/log/mysql/error.log. Für Docker müssen diese Konfigurationen geändert werden, damit die Anwendung nach stdout und stderr schreibt. Bei Nginx ist das eine einzeilige Änderung in der Konfiguration: access_log /dev/stdout; und error_log /dev/stderr;. Die offiziellen Docker-Images für Nginx, Apache und viele andere Dienste kommen bereits mit dieser Konfiguration.
Bei PHP-FPM ist es etwas komplexer: error_log = /proc/self/fd/2 in der PHP-FPM-Konfiguration leitet Fehler nach stderr, catch_workers_output = yes fängt die Ausgaben der Worker-Prozesse ab. In Magento-Projekten mit Docker muss man zusätzlich sicherstellen, dass das Magento-eigene Logging nicht nur in var/log/ schreibt, sondern kritische Fehler auch nach stderr weiterleitet. Ein Monolog-Handler für Docker Logs, der neben dem Datei-Handler auch einen Stream-Handler nach php://stderr konfiguriert, ist die sauberste Lösung.
| Log-Treiber | Speicherort | docker logs | Empfehlung |
|---|---|---|---|
| json-file | Host-Dateisystem | Ja | Entwicklung, mit Rotation |
| local | Host, komprimiert | Nein | Produktion ohne externes System |
| journald | systemd Journal | Ja | Linux-Hosts mit systemd |
| fluentd | Externer Aggregator | Nein | Enterprise, komplexe Pipelines |
| gelf | Graylog / Externer | Nein | Graylog-Infrastruktur |
9. Logging-Strategien im direkten Vergleich
Je nach Teamgröße, Infrastruktur und Compliance-Anforderungen gibt es verschiedene sinnvolle Logging-Strategien für Docker Logs. Die Wahl hängt vom Kontext ab: Ein kleines Team mit einem einzelnen Docker-Host hat andere Anforderungen als ein Unternehmen mit Dutzenden Microservices auf einem Kubernetes-Cluster.
Das wichtigste Kriterium ist die Observability: Können Logs bei einem Produktionsvorfall in unter einer Minute gefunden und gefiltert werden? Wenn nicht, ist die gewählte Strategie für Docker Logs nicht produktionsreif. Die zweite Frage betrifft die Persistenz: Logs, die nach einem Container-Neustart verloren gehen, sind für Post-mortem-Analysen wertlos. Und die dritte Frage betrifft die Alarmierung: Gibt es automatische Benachrichtigungen bei Error-Logs, ohne dass jemand aktiv die Logs beobachten muss?
Mironsoft
Docker Logging, Observability und Container-Infrastruktur
Docker Logs produktionsreif aufbauen?
Wir analysieren eure bestehende Logging-Infrastruktur, richten strukturiertes Logging mit dem richtigen Log-Treiber ein und bauen ein zentrales Log-Management-System mit Loki oder Elasticsearch auf.
Logging-Audit
Analyse der bestehenden Docker-Logs-Konfiguration und Identifikation von Schwachstellen
Loki-Setup
Zentrales Log-Management mit Grafana Loki, Promtail und Dashboards aufbauen
Alarmierung
Automatische Alerts bei Error-Logs in Slack, PagerDuty oder E-Mail einrichten
10. Zusammenfassung
Produktionsreife Docker Logs entstehen aus dem Zusammenspiel von vier Ebenen: Die Anwendung schreibt ausschließlich nach stdout und stderr. Der Log-Treiber leitet diese Ausgaben an das richtige Ziel weiter. Die Rotation verhindert unkontrollierten Speicherverbrauch. Und ein zentrales System wie Loki, Fluentd oder Elasticsearch macht Logs durchsuchbar und alarmierbar. Wer eine dieser vier Ebenen vernachlässigt, bemerkt das spätestens beim ersten Produktionsvorfall, wenn Logs entweder nicht auffindbar, nicht lesbar oder schlicht nicht vorhanden sind.
Strukturiertes Logging im JSON-Format ist die wichtigste einzelne Investition in die Qualität von Docker Logs. Sie kostet initial etwas Konfigurationsaufwand in der Anwendung, ermöglicht aber präzise Abfragen, automatische Feldextraktion und aussagekräftige Dashboards – ohne manuelle Log-Parsing-Regeln pflegen zu müssen. Container-Labels als automatische Metadaten und der richtige Log-Treiber für die Umgebung runden eine produktionsreife Logging-Strategie ab.
Docker Logs — Das Wichtigste auf einen Blick
stdout & stderr
Anwendungen müssen nach stdout/stderr schreiben. Dateien im Container erzeugen keine Docker Logs und verschwinden bei Container-Entfernung.
Log-Rotation
max-size und max-file in daemon.json oder pro Container konfigurieren. Ohne Rotation belegen Logs unbegrenzt Speicher.
Strukturiertes Logging
JSON-Format mit festen Feldern für Level, Service, Duration. Container-Labels automatisch als Metadaten hinzufügen.
Zentrales Log-Management
Loki + Promtail oder Fluentd für übergreifende Suche, Persistenz und automatische Alerts bei kritischen Fehlern.