Lassen Sie eine Docker-Anwendung in stdout schreiben

Ich stelle eine 3rd-Party-Anwendung in Übereinstimmung mit der bereit 12 faktor beratung, und einer der Punkte besagt, dass Anwendungsprotokolle in stdout / stderr gedruckt werden sollten: Dann kann Clustering-Software sie sammeln.

Die Anwendung kann jedoch nur in Dateien oder Syslog schreiben. Wie drucke ich stattdessen diese Protokolle aus?

Ein erstaunliches Rezept ist in der nginx-Docker-Datei:

# forward request and error logs to docker log collectorRUN ln -sf /dev/stdout /var/log/nginx/access.log \    && ln -sf /dev/stderr /var/log/nginx/error.log

Einfach gesagt, die App kann weiterhin als Datei darauf schreiben, aber als Ergebnis gehen die Zeilen zu stdout &S; stderr!

Für einen Hintergrundprozess in einem Docker-Container, z. B. Verbindung mit exec zu / bin / bash, konnte ich verwenden.

echo "test log1" >> /proc/1/fd/1

Dies sendet die Ausgabe an die Standardausgabe von pid 1, die von Docker abgeholt wird.

In einer anderen Frage, Kindprozess beenden, wenn der übergeordnete Prozess beendet wird, Ich habe die Antwort bekommen, die geholfen hat, das zu klären.

Auf diese Weise konfigurieren wir die Anwendung so, dass sie sich kontinuierlich in einer Datei anmeldet tail -f es. Glücklicherweise, tail kann annehmen --pid PID: es wird beendet, wenn der angegebene Prozess beendet wird. Wir setzen $$ dort: PID der aktuellen Shell.

Als letzten Schritt wird die gestartete Anwendung exec'ed, was bedeutet, dass die aktuelle Shell vollständig durch diese Anwendung ersetzt wird.

Runner-Skript, run.sh, wird so aussehen:

#! /usr/bin/env bashset -eurm -rf /var/log/my-application.logtail --pid $$ -F /var/log/my-application.log &exec /path/to/my-application --logfile /var/log/my-application.log

HINWEIS: durch die Verwendung von tail -F wir listen Dateinamen auf, und es wird sie lesen, auch wenn sie später erscheinen!

Schließlich das minimalistische Dockerfile:

FROM ubuntuADD run.sh /root/run.shCMD ['/root/run.sh']

Hinweis: um einige extrem seltsame Probleme zu umgehen tail -f verhalten (das besagt "wurde durch eine Remote-Datei ersetzt. diesen Namen aufgeben ") Ich habe einen anderen Ansatz ausprobiert: Alle bekannten Protokolldateien werden beim Start erstellt und abgeschnitten: Auf diese Weise stelle ich sicher, dass sie existieren, und erst dann -- tail:

#! /usr/bin/env bashset -euLOGS=/var/log/myapp/( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )tail --pid $$ -n0 -F $LOGS/* &exec /usr/sbin/apache2 -DFOREGROUND

für nginx können Sie haben nginx.conf zeigen auf /dev/stderr und /dev/stdout wie diese

user  nginx;worker_processes  4;error_log  /dev/stderr;http {    access_log  /dev/stdout  main;...

und deine Dockerfile eintrag sollte sein

/usr/sbin/nginx -g 'daemon off;'

In meinem Fall hat das Herstellen einer symbolischen Verknüpfung zu stdout nicht funktioniert, daher führe ich stattdessen den folgenden Befehl aus

ln -sf /proc/self/fd/1 /var/log/main.log 

Ich musste dieses Problem nur mit apache2 lösen und habe mit der Verwendung von CustomLog gerungen, um zu versuchen, zu umleiten /proc/1/fd/1 aber konnte das nicht zum Laufen bringen. In meiner Implementierung lief Apache nicht als pid 1, so antwort von kolypto hat nicht so funktioniert wie es ist. Pieters Ansatz schien überzeugend, also habe ich die beiden zusammengeführt und das Ergebnis funktioniert wunderbar:

# Redirect apache log output to docker log collectorRUN ln -sf /proc/1/fd/1 /var/log/apache2/access.log \    && ln -sf /proc/1/fd/2 /var/log/apache2/error.log

Technisch hält das den Apache access.log und error.log gehen zu stdout und stderr was den Docker-Protokollkollektor betrifft, aber es wäre großartig, wenn es eine Möglichkeit gäbe, die beiden zu trennen außerhalb der Container, wie ein Schalter für docker logs das würde nur das eine oder andere zeigen...

Sie können einen Daemon-Prozess syslog verwenden lassen und einen Front-Prozess haben, der druckt?

Sie gehen bereits zu Syslog. Sie können sie einfach von dort abholen!

@MichaelHampton, scheint in Ordnung zu sein, aber Docker führt einen einzelnen Prozess aus, der in stdout schreiben kann, und das klingt so, als würde man zwei davon kombinieren?

@qkrijger, guter Punkt! Nun, wenn jemand Erfahrung damit hat… ?