Hacer que una aplicación Docker escriba en stdout

Estoy implementando una aplicación de terceros de acuerdo con el asesoramiento de 12 factores, y uno de los puntos indica que los registros de la aplicación deben imprimirse en stdout/stderr: entonces el software de agrupación en clústeres puede recopilarlos.

Sin embargo, la aplicación solo puede escribir en archivos o syslog. ¿Cómo imprimo estos registros en su lugar?

Una receta increíble se da en el Archivo acoplable nginx:

# 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

Simplemente, la aplicación puede continuar escribiendo en ella como un archivo, pero como resultado las líneas irán a stdout &lificador; stderr!

Para un proceso en segundo plano en un contenedor docker, por ejemplo, conectándome con exec a /bin/bash, pude usar.

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

Esto envía la salida a la salida estándar de pid 1, que es la que recoge docker.

En otra pregunta, Matar el proceso secundario cuando el padre sale, Obtuve la respuesta que ayudó a resolver esto.

De esta forma, configuramos la aplicación para que se registre en un archivo y de forma continua tail -f se. Afortunadamente, tail puede aceptar --pid PID: se cerrará cuando salga el proceso especificado. Ponemos $$ allí: PID del shell actual.

Como paso final, la aplicación lanzada es exec'ed, lo que significa que el shell actual se reemplaza por completo con esa aplicación.

Guión de corredor, run.sh, se verá así:

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

NOTA: al usar tail -F enumeramos los nombres de los archivos, y los leerá incluso si aparecen más tarde.

Finalmente, el minimalista Dockerfile:

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

Nota: para solucionar algunos problemas extremadamente extraños tail -f comportamiento (que dice "ha sido reemplazado por un archivo remoto. renunciando a este nombre") probé otro enfoque: todos los archivos de registro conocidos se crean y truncan al inicio: de esta manera me aseguro de que existan, y solo entonces them los sigo:

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

para nginx puedes tener nginx.conf señalando a /dev/stderr y /dev/stdout como esto

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

y tu Dockerfile la entrada debe ser

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

En mi caso, hacer un enlace simbólico a stdout no funcionó, así que en su lugar ejecuto el siguiente comando

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

Solo tuve que resolver este problema con apache2 y luché con el uso de CustomLog para intentar redirigir a /proc/1/fd/1 pero no pude hacer que eso funcionara. En mi implementación, Apache no se ejecutaba como pid 1, tan la respuesta de kolypto no funcionó como está. El enfoque de Pieter parecía convincente, así que fusioné los dos y el resultado funciona de maravilla:

# 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

Técnicamente, esto mantiene el apache access.log y error.log ir a stdout y stderr en lo que respecta al recopilador de registros de docker, pero sería genial si hubiera una manera de separar los dos fuera el contenedor, como un interruptor para docker logs eso mostraría solo uno u otro...

¿Puede hacer que un proceso demonio use syslog y tenga un proceso frontal que imprima?

Ya van a syslog. ¡Puedes recogerlos desde allí!

@MichaelHampton, parece estar bien, pero Docker ejecuta un solo proceso que puede escribir en stdout, y esto suena como combinar dos de ellos.

@qkrijger, buen punto! Ahora, si alguien tiene experiencia con eso … ?