Happy Logging!

Top 10 Docker-Logging-Probleme, die jeder kennen sollte

Stefan Thies

© Shutterstock.com / Pavel Ignatov

Ein grundlegenden Kommando, das Docker-Anwender nach docker run kennenlernen, ist docker logs zur Anzeige der Container Logs – aber wussten Sie, dass dieses Kommando nicht immer funktioniert? Schade, aber wahr! Die Gründe dafür werden wir in diesem Artikel kennen lernen…

Docker hat nicht nur das Paketieren und Verteilen von Anwendungen radikal verändert, auch die Handhabung von Logs ändert sich mit dem Einsatz von Docker erheblich. Statt Logs in Dateien zu schreiben, sollten Container die Logausgabe auf die Konsole (Standardausgabe) schreiben.  Docker-Logging-Treiber leiten die Ausgaben der Container in Dateien oder an Logging-Dienste, wie Syslog, Journald oder Splunk weiter.

Eine Suche nach Problemen beim Logging im Github Repository von Docker zeigt, dass viele Docker-Anwender Schwierigkeiten haben. Die Handhabung von Containerlogs scheint knifflig zu sein. Zur Lösung dieser Probleme sind detaillierte Kenntnisse über die Implementierung von Docker-Logging-Treiber und deren Alternativen nötigt. Was sind die unangenehmsten oder häufigsten Schwierigkeiten? Hier sind die Top 10 der Docker-Probleme, die jeder Anwender kennen sollte.

Um ein besseres Verständnis der einzelnen Probleme zu bekommen, betrachten wir zunächst die Docker-Logging-Treiber und verschiedene Möglichkeiten, Logs zu zentralisierten. Außerdem werden wir Log-Management-Systeme wie Elastic Stack (bekannt als ELK Stack) oder entsprechende gehostete Lösungen wie Sematext Cloud betrachten.

Abb. 1: Die Docker-Logging-Treiber leiten die Ausgaben der Container in Dateien oder an Logging-Dienste weiter

Ursprünglich waren Containerlogs nur über das Docker Remote API zugänglich, dafür nutzte man das Kommando docker logs. Später hat Docker die Logging-Treiber eingeführt, um Docker für verschiedene Log-Management-Systeme und bekannte Log Shipper wie Syslog oder Journald zu öffnen. Diese Logging-Treiber sind als binäre Plug-ins für den Docker Daemon implementiert und sind Bestandteil des Docker-Daemon-Prozesses. Erst vor Kurzem wurde die Plug-in-Architektur für Logging-Treiber erweitert, um die Treiber als externe Prozesse auszuführen. Solche Logging-Plug-ins registrieren sich beim Docker Daemon und erhalten die Log-Events über Linux-FIFO-Dateien. Falls ein Plug-in abstürzt, wird der Docker-Daemon-Prozess nicht in Mitleidenschaft gezogen. Des Weiteren sind Implementierungen in anderen Programmiersprachen als Go möglich und müssen nicht im GitHub Repository für Docker eingepflegt werden. Die aktuell verfügbaren Logging-Treiber sind noch fester Bestandteil des Docker Daemon. Dies wird sich voraussichtlich bald ändern – ein unabhängiges Plug-in zur Weiterleitung von Logs zu Apache Kafka ist bereits verfügbar.

Docker-Logging-Treiber empfangen Containerlogs und leiten diese Logs an andere Systeme zur Analyse und Speicherung weiter. Der Standard-Logging-Treiber json-file speichert die Containerlogs im JSON-Format auf die Festplatte. Aufgrund der Plug-in-Architektur sind weiter Treiber für Open Source und kommerzielle Tools verfügbar:

  • Journald: Speichert Logs im Linux System Journal
  • Syslog: Weiterleitung an Syslog via UDP, TCP oder TLS
  • Fluentd: Weiterleitung an Fluentd via Unix- oder TCP-Socket
  • Splunk: HTTP/HTTPS-Weiterleitung an Splunk Server
  • Gelf: UDP-Weiterleitung an den Graylog Server

Für eine komplette Log-Management-Lösung werden jedoch weitere Tools benötigt:

  • Log Parser, um die Logs für spätere Analysen zu strukturieren. Typischerweise sind Parser in in Log Shipper Tools wie Fluentd, Rsyslog, Logstash oder Logagent implementiert
  • Log Indizierung für die Suche, Visualisierung und Alarmierung:
    • Elasticsearch und Kibana (Elastic Stack)
    • Splunk
    • Logentries
    • Loggly
    • Sumologic
    • Graylog  OSS / Enterprise
    • Sematext Cloud und Enterprise
    • und viele andere…

Um Logs an eins dieser Log-Management-Systeme zu senden, muss der entsprechende Docker-Logging-Treiber verwendet werden. Wenn Ihr Tool z. B. das Syslog-Protokoll benötigt, muss entsprechend der Docker-Syslog-Treiber verwendet werden.

1. Docker-Logs-Kommando funktioniert nur mit json-file oder Journald-Logging-Treiber

Der Standardtreiber json-file schreibt Logs auf die Festplatte und ist der einzige Logging-Treiber, der parallel zum Kommando docker logs funktioniert. Sobald alternative Logging-Treiber, also bspw. Syslog, Gelf oder Splunk, eingesetzt werden, gibt das Kommando docker logs eine Meldung über diese Einschränkung aus, anstatt die Log-Meldungen anzuzeigen. Aber nicht nur der Aufruf des Kommandos funktioniert nicht, auch die Aufrufe des Docker Remote API funktionieren nicht. Deshalb können in dieser Situation auch andere Tools keine Logs darstellen, die das Docker Remote API verwenden. Dies betrifft nicht nur Logging Tools wie Logspoud, auch das populäre Orchestrierungs-Tool Portainer.io ist davon betroffen: Logs werden nicht in der grafischen Benutzeroberfläche dargestellt.

Siehe: https://github.com/moby/moby/issues/30887

2. Docker-Syslog-Treiber kann das Deployment von Containern verhindern oder Container stoppen, wenn der Syslog-Server nicht verfügbar ist

Die Verwendung von des Syslog-Logging-Treibers mit TCP oder TLS bietet im Gegensatz zum UDP-Protokoll eine zuverlässige Möglichkeit, Logs zu einem Syslog-Server zu übertragen. Der Syslog-Treiber benötigt jedoch beim Starten eines Containers eine etablierte TCP/TLS-Verbindung zum Syslog-Server. Wenn diese Verbindung zum Startzeitpunkt des Containers nicht aufgebaut werden kann, schlägt der Start des Containers mit folgender Fehlermeldung fehl:

docker: Error response from daemon: Failed to initialize logging driver: dial tcp

Dies bedeutet, dass ein vorübergehendes Netzwerkproblem oder eine hohe Netzwerklatenz den Start von Containern blockieren könnte. Außerdem könnte ein Neustart des Syslog-Servers alle Container, die über TCP/TLS mit einem zentralen Syslog-Server verbunden sind, beenden. Eine Situation, die man unbedingt vermeiden sollte! Ein ähnliches Verhalten wurde auch beim Fluentd-Treiber berichtet, obwohl das Problem laut Dokumentation dort nicht bestehen sollte.

Siehe: https://github.com/moby/moby/issues/21966

3. Docker Syslog-Treiber verliert Logs, wenn der Syslog-Server nicht erreichbar ist

Ähnlich wie das obige Problem, das einen Verlust von Log-Events verursacht, ist die fehlende Fähigkeit einiger Docker-Logging-Treiber, Log-Events auf der Festplatte zu puffern, wenn sie nicht an die Zieladresse geliefert werden können. Man sollte auch dieses Thema weiter beobachten.

Siehe: https://github.com/moby/moby/issues/30979

4. Docker-Logging-Treiber unterstützen keine mehrzeiligen Log-Meldungen wie Java oder Node.js Stack Traces

Häufig denkt man bei Logmeldungen an einzeilige Benachrichtigungen (vergleichbar mit Logs von Webservern). Logmeldungen können sich aber auch über mehrere Zeilen erstrecken, Java Exceptions und Stack Traces sind ein gutes Beispiel für mehrzeilige Log-Meldungen. Logstash-Benutzer kennen das Problem der Handhabung von Stack Traces mit Logstash. In der Welt der Container ist es nicht besser. Es kann sogar noch komplizierter werden, weil Logs von verschiedenen Containern mit entsprechenden Parser-Regeln verarbeitet werden müssen. Kein Wunder, dass das Docker GitHub Issue #22920 ohne Lösung des Problems geschlossen wurde. Für die Interpretation mehrzeiliger Log-Meldungen fühlt man sich im Docker-Projekt nicht verantwortlich. Glücklicherweise gibt es Tools wie den Sematext Docker Agent, der mehrzeilige Logs in vielen Situationen ohne eine spezielle Konfiguration analysieren kann und benutzerdefinierte Parser-Regeln für Docker Images unterstützt.

5. Docker service logs-Befehl blockiert mit anderen Treibern als json-file

Während der json-file-Treiber robust wirkt, können andere Log-Treiber leider immer noch Probleme mit dem Docker-Swarm-Modus verursachen.

Siehe https://github.com/docker/docker/issues/28793

6. Docker Daemon stürzt ab, wenn der Fluentd Daemon nicht erreichbar und der Puffer voll ist

Ein weiteres Szenario, in dem ein Logging-Treiber Probleme verursacht, wenn das entfernte Ziel nicht erreichbar ist. In diesem speziellen Fall erzeugen die Logging-Treiber Fehler, die den Docker Daemon zum Absturz bringen.

7. Docker-Container bleibt im Status created bei Fehlermeldung des Splunk-Servers

Wenn der Splunk-Server beim Start des Containers den HTTP-Fehlerstatus 504 liefert, wird der Container tatsächlich gestartet, Docker meldet den Start des Containers allerdings als fehlgeschlagen. In diesem Zustand erscheint der Container nicht mehr unter docker ps, und der Containerprozess kann nicht mehr mit docker kill gestoppt werden. Die einzige Möglichkeit zum Stoppen des Prozesses besteht darin, ihn manuell zu beenden.

Siehe: https://github.com/moby/moby/issues/24376

8. Docker verliert Log-Meldungen mit Journald-Treiber

Es stellte sich heraus, dass dieses Problem durch die Journald Rate Limits verursacht wird. Die maximale Lograte muss erhöht werden, weil Docker-Logs für alle laufenden Container erstellt und Journald einige Logs aufgrund der Einstellungen für die Rate Limits überspringen könnte. Achten Sie daher auf Ihre Journald-Einstellungen, wenn Sie Docker mit dem Journald-Treiber verwenden.

9. Fehlende Logs mit Gelf-Logging-Treiber bei Änderung der IP-Adresse

Dem Gelf-Logging-Treiber fehlt eine TCP- oder TLS-Option, denn er unterstützt nur die effiziente Übertragung mit UDP. Logmeldungen könnten verloren gehen, wenn es zum Verlust von UDP-Paketen kommt. Es wurden auch Probleme mit der DNS-Auflösung/Caching mit Gelf-Treibern berichtet. Dies hat ggf. zur Folge, dass Logmeldungen ins Nirvana gesendet werden, wenn sich die IP-Adresse ihres Graylog-Servers ändert. Denn der Gelf-Treiber löst die Adresse des Graylog-Servers nur beim Start eines Containers auf und durch die Verwendung von UDP kann der Treiber nicht feststellen, dass die Logmeldungen beim Graylog-Server gar nicht ankommen.

Siehe: https://github.com/moby/moby/issues/23679

10. Docker unterstützt nur einen Logging-Treiber

Es wäre optimal, wenn die Containerlogs sowohl lokal auf dem Server gespeichert als auch an Server versendet werden könnten. Zurzeit unterstützt Docker leider nur einen Logging-Treiber, sodass Benutzer gezwungen sind, sich für einen Logging-Treiber zu entscheiden. Keine leichte Entscheidung, wenn man die hier aufgelisteten Probleme verschiedener Logging-Treiber kennt!

Alternativen für das Logging

Soweit die „Top 10 Docker Logging Probleme“. Angesichts der vielseitigen Schwierigkeiten beim Docker Logging stellt man sich die Frage: „Was ist die Alternative für zuverlässiges Logging mit Docker?“

Zunächst sollte man sich über mögliche Probleme bei dem gewünschten Logging-Treiber informieren und entsprechende Maßnahmen treffen. Viele Schwierigkeiten lassen sich vermeiden, wenn man sich möglicher Fehlerquellen bewusst ist! Eine Alternative bietet ggf. die Kombination aus json-file Logging-Treiber und API-basierten Logging Tools:

  1. Der json-file-Treiber ist der Standard-Logging-Treiber und ist sehr zuverlässig. Eine lokale Kopie der Logs ist auf dem Server verfügbar, das Kommando docker logs und entsprechende Aufrufe des Docker API funktionieren.
  2. Filterung der Log-Events mit dynamischen Kriterien, wie Image-Name oder Container-Labels.
  3. Detaillierte Container-Metadaten durch den Zugriff auf das Docker Remote API. Insbesondere beim Einsatz von Docker Swarm und Kubernetes sind zusätzliche Metadaten (Pod-Name, Service-Name, Image-Name, Namespace, Task ID etc.) notwendig und eine Kennzeichnung der Logs nur mit der ContainerID und Image-Namen nicht ausreichend.
  4. Geringes Risiko, dass Docker durch einen Fehler im Logging-Treiber abstürzt. Auf dem Docker API basierende Logging Tools laufen als separater Container mit ggf. limitierten Ressourcen und sind so vom Docker-Daemon-Prozess entkoppelt.

Logspout vs. Sematext Docker Agent vs. Elastic Filebeat

Wir wollen nun zwei Open Source Tools der Kategorie „Docker API basierte Log Shipper“ näher betrachten: Logspout und Sematext Docker Agent. Als drittes Tool kommt im weiteren Sinne auch Elastic Filebeat in Frage, das jedoch das Docker API nur zur Anreicherungen von Logs mit Metadaten verwendet und die Log-Events aus Dateien liest, die vom json-file-Treiber erzeugt werden. Eine Gegenüberstellung der drei Tools befindet sich in Tabelle 1.

Logspout bietet mehrere Plug-ins (Syslog, Apache Kafka, Logstash etc.) für die Logausgabe an. Das interessanteste an Logspout ist die Möglichkeit, die Log-Events der einzelnen Container zu unterschiedlichen Zielen zu senden. Mit diesem Log Routing kann man also die Log-Events verschiedener Anwendungen an verschiedene Server senden, sodass  mehrere Teams jeweils ihre eigenen Logs selbst verwalten können. Logspout entfernt auch ANSI-Escape-Sequenzen in Logs, die für die farbige Ausgabe im Terminal verwendet werden, aber bei der Indizierung von Logs in Elasticsearch Probleme verursachen. Die Log-Events werden durch die ANSI-Escape-Sequenzen falsch indiziert und Suchanfragen liefern evtl. keine Resultate für farbige Logmeldungen. Deshalb ist die Entfernung der ANSI-Escape-Sequenzen ein sinnvolles Feature.

Abb. 2: Logspout bietet mehrere Plug-ins für die Logausgabe an

Logspout war offensichtlich ein Vorbild für den Sematext Docker Agent (SDA), denn dieser basiert auch auf dem Docker Remote API, unterstützt Log Routing und kann ANSI-Escape-Sequenzen für die Volltextsuche in Elasticsearch richtig verarbeiten. Allerdings ist der Sematext Docker Agent mehr als ein einfacher Log Shipper. Das Tool bietet Lösungen für mehrere der genannten Probleme an und hat hilfreiche Zusatzfunktionen:

  • Handhabung von mehrzeiligen Logmeldungen
  • Zuverlässige Übertragung der Log-Events durch Pufferung der Logs auf der Festplatte, wenn diese nicht in Elasticsearch indiziert werden können. Dies vermeidet den Verlust von Log Events, falls Elasticsearch temporär nicht verfügbar ist oder die Indizierung aufgrund eines falschen Schemas temporär fehlschlägt.
  • Übertragung der Logs über HTTPS zu Elasticsearch, Sematext Cloud (EU, US) oder Sematext Enterprise.
  • Maskierung sensitiver Felder (Kreditkartennummern, Telefonnummern etc.) durch SHA256 oder SHA512 Hash Codes.
  • Erkennung der Logformate und Parser-Konfigurationen für populäre Anwendungen wie Nginx, Apache, Elasticsearch, Solr, Kafka, HBase, MongoDB etc.
  • Anreicherung der Logs mit Metadaten für Kubernetes, Docker Swarm und Docker Compose
  • Anreicherung der Logs mit Daten aus Umgebungsvariablen und Container Labels
  • Anreicherung von Webserver Logs mit Standortangaben aus der Maxmind-GeoIP-Datenbank

Abb. 3: Der Sematext Docker Agent basiert auf dem Docker Remote API, unterstützt Log Routing und kann ANSI-Escape-Sequenzen für die Volltextsuche in Elasticsearch richtig verarbeiten

Der Quellcode des Sematext Docker Agent ist Open Source auf GitHub verfügbar und kann mit dem Elastic Stack oder Sematext Cloud verwendet werden. Zusatzfunktionen, wie das Performance Monitoring von Containern und Docker Hosts sowie das Sammeln der Docker Events funktionieren nur mit der Sematext Cloud. Die genannten Logging-Funktionen funktionieren jedoch mit jedem Elasticsearch Cluster.

Elastic Filebeat Gliderlabs Logspout Sematext Docker Agent
  • Sammeln von Log-Events aus Dateien, die der Docker json-file-Treiber generiert. Die Anreicherung mit Metadaten (Containername, Image-Name und Labels) erfolgt über das Docker Remote API.
  • Log Events können zu Elasticsearch, Apache Kafka, Logstash oder Redis gesendet werden.
  • Sammeln von Log Events und Metadaten mittels Docker Remote API. Log-Events können zu Syslog oder HTTP-Servern gesendet werden.
  • Plug-ins erlauben die Weiterleitung der Log-Events zu Apache Kafka, Logstash, Gelf (Graylog) oder Redis.
  • Sammelt Log-Events, Docker Events und Metriken mittels Docker Remote API.
  • Die Anreicherung der Metadaten für Kubernetes, Docker Swarm, Docker Compose, Docker Cloud, Labels und Umgebungsvariablen erfolgt ebenfalls aus Daten, die über das Docker Remote API verfügbar sind.
  • GeoIP-Daten werden mittels Maxmind-GeoIP-Datenbank ermittelt.
  • Log-Events können an Elasticsearch oder Sematext Cloud (Europa und USA) weitergeleitet werden. Metriken sind nur in Sematext Cloud verfügbar.
  • Kein Log Routing, d.h. man kann Logs von unterschiedlichen Containern nicht direkt zu verschiedenen Zielen leiten (Link). Dies müsste ggf. in Logstash realisiert werden.
  • Log Routing wird unterstützt.
  • Mehrere Ziele für Log-Events können über Container-Labels adressiert werden.
  • Log Routing mittels Container-Labels und Umgebungsvariablen wird unterstützt.
  • Die Labels enthalten den Namen des Elasticsearch-Index‘ oder der Sematext Cloud Tokens.
  • Das Routing ist dadurch flexibel, weil jedes Team eigene Indizes beim Start von Containern angeben kann, ohne die Konfiguration des Agents anzupassen.
  • Mehrzeilige Log Events können bei entsprechender Konfiguration verarbeitet werden. Allerdings kann nur ein globaler regulärer Ausdruck zum Aufteilen der Logmeldungen konfiguriert werden, was ggf. bei unterschiedlichen Logformaten der Anwendungen kompliziert werden kann.
  • Keine Unterstützung für mehrzeilige Logs. Dies muss ggf. mit zusätzlichen Tools wie Logstash Fluentd oder Logagent realisiert werden.
  • Mehrzeilige Log-Events werden direkt unterstützt, sodass Java oder Node.js Stack Traces oder Meldungen, die mit Tab oder Space eingerückt sind, automatisch erkannt werden. Der verwendete reguläre Ausdruck kann angepasst werden. Zusätzliche Parser-Regeln können in einer Konfigurationsdatei eingestellt werden, um eine anwendungsspezifische Aufteilung (z. B. pro Container-Image) von mehrzeiligen Logs vorzunehmen. So kann man z. B. Blöcke, die mit einem Datum beginnen, als Trenner für die Log-Meldung definierten.
  • Log Events können anhand von Docker-Metadaten (Container-Name, Image-Name, Labels) gefiltert werden.
Filterung mittels Wildcard-Ausdrücken, die auf Container-Labels passen.
  • Blacklist- und Whitelist-Filter mittels regulärem Ausdruck für ContainerID, Image-Name, Container Name.
  • Zusätzlich sind Filter mittels Labels möglich, die explizit die Sammlung von Log-Events pro Container ein oder ausschalten.
  • Keine Pufferung von Log-Events.
  • Logs könnten verloren gehen, wenn die Weiterleitung fehlschlägt.
  • Keine Pufferung von Log Events.
  • Logs könnten verloren gehen, wenn die Weiterleitung fehlschlägt.
  • Pufferung von Logs in einem Docker Volume wird unterstützt.
  • Log-Events, deren Weiterleitung fehlgeschlagen ist, werden gespeichert und später erneut übertragen. Der Puffer wird bei Überschreitung von eingestellten Grenzwerten aufgeräumt, indem die ältesten Dateien gelöscht werden.
  • Kein Log-Parser für Containerlogs.
  • Der integrierte JSON Parser extrahiert lediglich Zeit, ContainerID und den Nachrichtentext aus den Docker-Log-Dateien, die im JSON-Format vorliegen.
  • Erfolgt die Ausgabe direkt in Elasticsearch, werden die Log-Meldungen (aus dem Feld „Message“) nicht geparst, dazu ist eine weitere Verarbeitung in Logstash oder die Verwendung von Elasticsearch Ingestion-Nodes notwendig.
    Filebeat „modules“ sind im Betastadium und können zurzeit noch nicht zum parsen von Containerlogs angewendet werden.
  • Logspout enthält keinen Log Parser. Auch hier könnte man Logspout mit Logstash, fluentd oder rsyslog kombinieren, um Logs vor dem indizieren in Elasticsearch zu parsen.
  • Umfangreicher Log Parser mit Erkennung der Logformate. Das JSON-Format und bereits im Paket enthaltene Muster zur Datenextraktion, z. B. für Nginx, Apache Webserver, MySQL, MongodDB, Solr, Cassandra oder Elasticsearch, werden automatisch verwendet.
  • Individuelle Muster für die Parser können für jedes Container-Image definiert werden. Dies schließt auch Funktionen für das Filtern oder die Transformation der geparsten Daten ein. Die Parser-Konfiguration kann über HTTP (z. B. GitHub Gist) oder eingebundene Docker Volumes geladen werden.
  • Das offizielle Filebeat Docker Image docker.elastic.co/beats/filebeat ist nur über die Docker Registry der Firma Elastic verfügbar.
  • Für Filebeat gibt es kein offizielles Image auf Docker Hub, allerdings sind einige alternative Images von verschiedenen Anbietern verfügbar.

Fazit

Aktuell würde ich eine klare Empfehlung für den json-file Docker Logging-Treiber in Kombination mit einem Docker-API-basierten Log Shipper aussprechen. Diese Kombination bietet Zuverlässigkeit und alle relevante Metadaten für die Loganalyse mit dem Elastic Stack. Dies mag sich jedoch in Zukunft ändern, denn Docker-Logging-Treiber werden sich verbessern und der neue Plug-in-Mechanismus, der es erlaubt, Logging-Plug-ins als externe Prozesse zu starten, verspricht bessere Stabilität. Docker hat die genannten Probleme erkannt und bietet mit der verbesserten Logging-Architektur die Grundlage für neue Logging-Plug-ins. Nun sind wiederum die Hersteller von Logging Tools am Zug, um das neue Plug-in-API zu implementieren, was sicherlich noch etwas Zeit in Anspruch nehmen wird. In der Zwischenzeit sind Filebeat, Logspout, Sematext Docker Agent praktikable Alternativen, die es erlauben, einige der Top 10 Docker Logging-Probleme zu umschiffen und gleichzeitig detaillierte Metadaten und besser strukturierte Logs für die Loganalyse zu erhalten.

Verwandte Themen:

Geschrieben von
Stefan Thies
Stefan Thies
Stefan Thies beschäftigt sich leidenschaftlich mit neuen Softwaretechnologien und skalierbaren Systemarchitekturen. Er hilft bei der Entwicklung zahlreicher Open Source Node.js-Projekte, die typischerweise etwas mit Monitoring, Logging oder verteilten Systemen zu tun haben. Er ist DevOps Evangelist bei Sematext Group, Inc. und Gründer von bigdata-analyst.de.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.