86 votes

Faire en sorte qu'une application Docker écrive sur stdout

Je suis en train de déployer une application tierce en conformité avec la norme Avis sur le facteur 12 et l'un des points indique que les journaux d'application doivent être imprimés sur stdout/stderr : le logiciel de clustering peut alors les collecter.

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

0 votes

Ils vont déjà dans le syslog. Vous pouvez simplement les récupérer à partir de là !

0 votes

@MichaelHampton, cela semble bien, mais Docker exécute un seul processus qui peut écrire sur stdout, et cela ressemble à la combinaison de deux d'entre eux ?

1 votes

Vous pouvez avoir un processus démon qui utilise syslog et avoir un processus frontal qui imprime ?

163voto

kolypto Points 10468

Une recette étonnante est donnée dans le nginx Dockerfile :

# 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 à y écrire en tant que fichier, mais en conséquence les lignes iront à stdout & stderr ¡!

5 votes

Ceci. Est. Juste. Brillant. Et polyvalent.

15 votes

La seule chose qui pose problème, c'est lorsque la chose que vous exécutez insiste pour passer en arrière-plan en tant que processus non racine. J'ai ce problème avec squid3 et il a ensuite des problèmes avec les permissions sur /dev/stdout .

9 votes

Cela ne fonctionne pas toujours - par exemple, si l'application tente de rechercher le fichier, cette méthode ne fonctionnera généralement pas.

54voto

Pieter Points 618

Pour un processus d'arrière-plan dans un conteneur docker, par exemple en se connectant avec exec à /bin/bash, j'ai pu utiliser.

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

Cela envoie la sortie vers le stdout de pid 1, qui est celui que docker récupère.

6 votes

C'est la bonne réponse. Les journaux doivent être envoyés à stdout pour PID1 et si votre application s'exécute sous un autre PID, il ne sera pas vu par docker logs o kubectl logs . J'ai un conteneur qui planifie une tâche par le biais de crontab qui ne fonctionne pas comme PID1.

0 votes

@leeman24 ce n'est pas correct : tout processus bifurqué de PID1 héritera de tous les FDs ouverts, y compris stdout y stderr c'est-à-dire le stdout des processus bifurqués seront collectés par docker logs également. Ce n'est que si un processus bifurqué ferme ou change son stdout à quelque chose d'autre, il ne sera pas disponible en docker logs plus. Puis vous pouvez utiliser /proc/1/fd/1 pour "reconnecter" la sortie à docker logs .

1 votes

Le plus simple, le plus facile, le plus fiable.

19voto

kolypto Points 10468

Dans une autre question, Tue le processus enfant quand le parent sort J'ai reçu la réponse qui m'a aidé à résoudre ce problème.

De cette façon, nous configurons l'application pour qu'elle enregistre dans un fichier, et en permanence tail -f il. Heureusement, tail peut accepter --pid PID il se terminera lorsque le processus spécifié se terminera. Nous mettons $$ là : PID du Shell actuel.

Dans une dernière étape, l'application lancée est exec 'ed, ce qui signifie que le Shell actuel est complètement remplacé par cette application.

Runner script, run.sh ressemblera à 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 -F on liste les noms de fichiers, et il les lira même s'ils apparaissent plus tard !

Enfin, le Dockerfile minimaliste :

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

Note : pour travailler sur des sujets extrêmement étranges tail -f J'ai essayé une autre approche : tous les fichiers journaux connus sont créés et tronqués au démarrage : de cette façon, je m'assure qu'ils existent, et seulement ensuite, je les tronque :

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

0 votes

En particulier pour le serveur Apache, j'utilise les logs pipés ( httpd.apache.org/docs/2.4/logs.html#piped ) et il semble que cela fonctionne.

0 votes

Cela résout des problèmes similaires avec alpine et semble fonctionner correctement avec BusyBox. tail sans l'option --pid.

0 votes

La solution de contournement a fonctionné pour moi. extrêmement utile, merci.

7voto

Nidhal Hack Points 21

Pour nginx vous pouvez avoir nginx.conf pointant vers /dev/stderr y /dev/stdout comme ceci

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

et votre Dockerfile l'entrée doit être

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

5 votes

Ne fonctionne pas lorsque le processus maître n'est pas en cours d'exécution comme root

3voto

Ali Hussein Points 31

Dans mon cas, faire un lien symbolique vers stdout n'a pas fonctionné, donc à la place j'ai exécuté la commande suivante

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

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X