Faire une application Docker écrire sur stdout

49

Je déploie une application tierce conformément à l'avis 12 , et l'un des points indique que les journaux d'application doivent être imprimés sur stdout / stderr: les logiciels de clustering peuvent le collecter.

Cependant, l'application ne peut écrire que dans des fichiers ou dans syslog. Comment puis-je imprimer ces journaux à la place?

Kolypto
la source
Ils vont déjà à syslog. Vous pouvez simplement les prendre à partir de là!
Michael Hampton
@ MichaelHampton, semble bien, mais Docker exécute un processus unique qui peut écrire sur la sortie standard, et cela ressemble à la combinaison de deux d'entre eux?
Kolypto
1
Vous pouvez avoir un processus démon qui utilise syslog et un processus frontal qui imprime?
Qkrijger
@qkrijger, bon point! Maintenant, si quelqu'un a de l'expérience avec ça ...?
Kolypto

Réponses:

107

Une recette étonnante est donnée dans le Dockerfile de 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

Simplement, l'application peut continuer à écrire dans un fichier, mais les lignes iront à stdout& stderr!

Kolypto
la source
2
Cette. Est. Juste. Brillant. Et polyvalent.
Spacediver
11
La seule chose qui pose problème, c’est que ce que vous exécutez insiste pour passer au second plan en tant que processus non root. Je suis avec cela squid3, et il a ensuite des problèmes avec les autorisations sur /dev/stdout.
mikepurvis
4
Cela ne fonctionne pas toujours. Par exemple, si l'application tente de rechercher le fichier, cette méthode ne fonctionnera généralement pas.
Mixja
Le lien est en panne ...
Babken Vardanyan
4
Tout est un fichier pour la victoire.
RubberDuck
16

Dans une autre question, processus enfant Kill lorsque le parent quitte , j'ai eu la réponse qui a aidé à résoudre ce problème.

De cette façon, nous configurons l’application pour qu’elle se connecte à un fichier et en continu tail -f. Heureusement, tailpeut accepter --pid PID: il se fermera à la fin du processus spécifié. Nous $$y mettons : PID du shell actuel.

Enfin, l’application lancée est exec'ed, ce qui signifie que le shell actuel est complètement remplacé par cette application.

Le script du coureur run.shressemblera à ceci:

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

NOTE: en utilisant tail -Fnous listons les noms de fichiers, et ils les liront même s'ils apparaissent plus tard!

Enfin, le fichier minimaliste Dockerfile:

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

Remarque: pour éviter un tail -fcomportement extrêmement étrange (qui dit "a été remplacé par un fichier distant. Abandonnant ce nom"), j’ai essayé une autre approche: tous les fichiers journaux connus sont créés et tronqués au démarrage: de cette manière, je les vérifie. , et alors seulement - les suivre:

#! /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
la source
Surtout pour le serveur Apache, j'utilise des journaux Piped ( httpd.apache.org/docs/2.4/logs.html#piped ) et j'ai l' impression que cela fonctionne.
php-codeur
tailCela résout des problèmes similaires avec alpine et semble bien fonctionner sur BusyBox sans l'option --pid.
Ryan
la solution a fonctionné pour moi. extrême utile, merci.
Tamas Kalman Le
8

Pour un processus en arrière-plan dans un conteneur de menu fixe, par exemple, la connexion avec exec à / bin / bash, je pouvais utiliser.

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

Cela envoie la sortie à la sortie standard du pid 1, qui est le premier docker capté.

Pieter
la source
1
C'est la bonne réponse. Les journaux doivent être envoyés à stdout pour PID1 et si votre application est exécutée sous un autre PID, elle ne sera pas vue par docker logsou kubectl logs. J'ai un conteneur qui planifie la tâche via crontab qui ne s'exécute pas en tant que PID1.
leeman24
6

pour nginx vous pouvez avoir en nginx.confmontrant /dev/stderret /dev/stdoutcomme celui - ci

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

et votre Dockerfileentrée devrait être

/usr/sbin/nginx -g 'daemon off;'
Muayyad Alsadi
la source
Ne fonctionne pas lorsque le processus maître ne fonctionne pas commeroot
Peedee