Fai scrivere un'applicazione Docker su stdout


49

Sto distribuendo un'applicazione di terze parti in conformità con la consulenza sui 12 fattori , e uno dei punti indica che i registri delle applicazioni devono essere stampati su stdout / stderr: quindi il software di clustering può raccoglierla.

Tuttavia, l'applicazione può scrivere solo su file o syslog. Come stampare invece questi registri?


Stanno già andando a syslog. Puoi semplicemente prenderli da lì!
Michael Hampton

@MichaelHampton, sembra che vada bene, ma Docker esegue un singolo processo che può scrivere su stdout, e questo suona come combinandone due?
Kolypto,

1
Puoi avere un processo daemon usare syslog e avere un processo frontale che stampa?
qkrijger,

@qkrijger, buon punto! Ora, se qualcuno ha esperienza con esso ...?
Kolypto,

Risposte:


107

Una straordinaria ricetta è data nel Dockerfile nginx :

# 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

Semplicemente, l'app può continuare a scriverla come file, ma di conseguenza le linee andranno a stdout& stderr!


2
Questo. È. Appena. Brillante. E versatile.
spaziatore

11
L'unica cosa che è un problema con questo è quando la cosa che stai eseguendo insiste nel forking se stesso in background come un processo non root. Sto avendo questo con squid3, e quindi ha problemi con le autorizzazioni /dev/stdout.
mikepurvis,

4
Questo non funziona sempre, ad esempio se l'applicazione tenta di cercare il file, questo metodo generalmente non funziona.
Mixja,

Il link non funziona ...
Babken Vardanyan,

4
Tutto è un file per la vittoria.
RubberDuck,

16

In un'altra domanda, uccidi il processo figlio quando il genitore esce , ho ottenuto la risposta che mi ha aiutato a risolvere questo problema.

In questo modo, configuriamo l'applicazione in modo che registri su un file e continuamente tail -f. Fortunatamente, tailpuò accettare --pid PID: uscirà quando termina il processo specificato. Mettiamo $$lì: PID della shell corrente.

Come passaggio finale, l'applicazione avviata viene exec"modificata", il che significa che la shell corrente viene completamente sostituita con tale applicazione.

Runner script, run.shsarà simile al seguente:

#! /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

NOTA: usando tail -Felenchiamo i nomi dei file, e li leggerà anche se compaiono in seguito!

Infine, il Dockerfile minimalista:

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

Nota: per ovviare a un tail -fcomportamento estremamente strano (che dice "è stato sostituito con un file remoto. Rinunciando a questo nome") ho provato un altro approccio: tutti i file di registro noti vengono creati e troncati all'avvio: in questo modo mi assicuro che esistano e solo allora - seguili:

#! /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

Soprattutto per il server Apache sto usando i log di Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) e sembra che funzioni.
php-coder,

Risolve problemi simili con alpine e sembra funzionare bene su BusyBox tailsenza l'opzione --pid.
Ryan,

la soluzione ha funzionato per me. estremamente utile, grazie.
Tamas Kalman,

8

Per un processo in background in un contenitore docker, ad esempio collegandomi con exec a / bin / bash sono stato in grado di usare.

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

Questo invia l'output allo stdout di pid 1, che è il pickup di una finestra mobile.


1
Questa è la risposta corretta I registri devono essere inviati a stdout per PID1 e se l'applicazione è in esecuzione con un altro PID, non verrà visualizzata da docker logso kubectl logs. Ho un contenitore che pianifica attività tramite crontab che non è in esecuzione come PID1.
leeman24,

6

per nginx puoi nginx.confpuntare a /dev/stderre in /dev/stdoutquesto modo

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

e la tua Dockerfilevoce dovrebbe essere

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

Non funziona quando il processo principale non è in esecuzione comeroot
peedee il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.