Erstellen Sie eine Docker-Anwendung, die in stdout schreibt

49

Ich stelle eine Drittanbieteranwendung gemäß dem 12-Faktor- Hinweis bereit. Einer der Punkte besagt, dass Anwendungsprotokolle in stdout / stderr gedruckt werden sollten. Dann kann die Cluster-Software sie erfassen.

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

kolypto
quelle
Sie gehen bereits zu Syslog. Sie können sie einfach von dort abholen!
Michael Hampton
@MichaelHampton, scheint in Ordnung zu sein, aber Docker führt einen einzelnen Prozess aus, der in stdout schreiben kann, und das klingt wie das Kombinieren von zwei davon?
kolypto
1
Sie können einen Daemon-Prozess verwenden Syslog und haben einen Front-Prozess, der druckt?
Qkrijger
@ qkrijger, guter Punkt! Nun, wenn jemand Erfahrung damit hat ...?
kolypto

Antworten:

107

Ein erstaunliches Rezept finden Sie in der Nginx Docker-Datei :

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

Die App kann einfach weiter als Datei darauf schreiben, die Zeilen gehen dann jedoch zu stdout& stderr!

kolypto
quelle
2
Diese. Ist. Gerade. Brillant. Und vielseitig.
Spaceriver
11
Das Problem dabei ist, dass das, was Sie ausführen, darauf besteht, sich als Nicht-Root-Prozess in den Hintergrund zu stellen. Ich habe dies mit squid3, und es hat dann Probleme mit Berechtigungen auf /dev/stdout.
Mikepurvis
4
Dies funktioniert nicht immer - wenn die Anwendung beispielsweise versucht, die Datei zu suchen, funktioniert diese Methode im Allgemeinen nicht.
Mixja
Link ist down ...
Babken Vardanyan
4
Alles ist eine Datei für den Gewinn.
RubberDuck
16

In einer anderen Frage, Prozess Kind töten, wenn das Elternteil beendet wird , erhielt ich die Antwort, die dazu beitrug, dies zu klären.

Auf diese Weise konfigurieren wir die Anwendung so, dass sie in einer Datei protokolliert und kontinuierlich ausgeführt tail -fwird. Zum Glück tailkann akzeptieren --pid PID: Es wird beendet, wenn der angegebene Prozess beendet wird. Wir setzen $$dort: PID der aktuellen Shell.

Als letzter Schritt wird die gestartete Anwendung execbearbeitet, was bedeutet, dass die aktuelle Shell vollständig durch diese Anwendung ersetzt wird.

Das Runner-Skript run.shsieht folgendermaßen aus:

#! /usr/bin/env bash
set -eu

rm -rf /var/log/my-application.log
tail --pid $$ -F /var/log/my-application.log &

exec /path/to/my-application --logfile /var/log/my-application.log

HINWEIS: Bei Verwendung von tail -Flisten wir die Dateinamen auf und sie werden gelesen, auch wenn sie später erscheinen!

Zum Schluss das minimalistische Dockerfile:

FROM ubuntu
ADD run.sh /root/run.sh
CMD ['/root/run.sh']

Hinweis: Um ein ungewöhnliches tail -fVerhalten zu vermeiden ("wurde durch eine entfernte Datei ersetzt. Diesen Namen aufgeben"), habe ich einen anderen Ansatz gewählt: Alle bekannten Protokolldateien werden beim Start erstellt und abgeschnitten. Auf diese Weise stelle ich sicher, dass sie existieren und erst dann - schwinge sie:

#! /usr/bin/env bash
set -eu

LOGS=/var/log/myapp/

( umask 0 && truncate -s0 $LOGS/http.{access,error}.log )
tail --pid $$ -n0 -F $LOGS/* &

exec /usr/sbin/apache2 -DFOREGROUND
kolypto
quelle
Speziell für Apache-Server verwende ich Piped-Protokolle ( httpd.apache.org/docs/2.4/logs.html#piped ) und es sieht so aus, als würde es funktionieren.
PHP-Coder
Das tailProgramm löst ähnliche Probleme mit Alpine und scheint auf BusyBox ohne die Option --pid problemlos zu funktionieren.
Ryan
Die Problemumgehung hat für mich funktioniert. extrem nützlich, danke.
Tamas Kalman
8

Für einen Hintergrundprozess in einem Docker-Container, zB Verbinden mit exec nach / bin / bash, konnte ich verwenden.

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

Dadurch wird die Ausgabe an die Standardausgabe von PID 1 gesendet, bei der es sich um die einzige Docker-Abholung handelt.

Pieter
quelle
1
Das ist die richtige Antwort. Die Protokolle sollten für PID1 an stdout gesendet werden. Wenn Ihre Anwendung unter einer anderen PID ausgeführt wird, wird sie von docker logsoder nicht angezeigt kubectl logs. Ich habe einen Container, der Task über Crontab plant, der nicht als PID1 ausgeführt wird.
leeman24
6

für nginx kann man darauf nginx.confzeigen /dev/stderrund das /dev/stdoutmögen

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

und Ihr DockerfileEintrag sollte sein

/usr/sbin/nginx -g 'daemon off;'
Muayyad Alsadi
quelle
Funktioniert nicht , wenn Master - Prozess nicht ausgeführt wird, wieroot
peedee