Faça um aplicativo Docker escrever para stdout

Estou implantando um aplicativo de terceiros em conformidade com o 12 factor advisory, e um dos pontos diz que os logs do aplicativo devem ser impressos em stdout / stderr: então o software de cluster pode coletá-lo.

No entanto, o aplicativo só pode gravar em arquivos ou syslog. Como faço para imprimir esses logs?

Uma receita incrível é dada no nginx Dockerfile:

# 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

Simplesmente, o aplicativo pode continuar gravando nele como um arquivo, mas como resultado as linhas irão para stdout &lificador; stderr!

Para um processo em segundo plano em um contêiner docker, por exemplo, conectando-se com exec para /bin/bash que pude usar.

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

Isso envia a saída para o stdout do pid 1,que é o único captador docker.

Em outra questão, Matar o processo filho quando o pai sai, Recebi a resposta que ajudou a resolver isso.

Dessa forma, configuramos o aplicativo para que ele faça logon em um arquivo e continuamente tail -f ele. Felizmente, tail pode aceitar --pid PID: ele sairá quando o processo especificado sair. Nós colocamos $$ lá: PID do shell atual.

Como etapa final, o aplicativo lançado é exec"ed, O que significa que o shell atual é completamente substituído por esse aplicativo.

Runner script, run.sh, ficará assim:

#! /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: usando tail -F listamos nomes de arquivos, e ele os lerá mesmo que apareçam mais tarde!

Finalmente, o Dockerfile minimalista:

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

Nota: para workaroung alguns extremamente estranho tail -f comportamento (que diz "foi substituído por um arquivo remoto. desistindo deste nome") tentei outra abordagem: todos os arquivos de log conhecidos são criados & amp; truncado no arranque: desta forma eu garantir que eles existem, e só então-cauda-los:

#! /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 você pode ter nginx.conf apontando para /dev/stderr e /dev/stdout comer

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

e o teu Dockerfile a entrada deve ser

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

No meu caso, fazer um link simbólico para stdout não funcionou, então, em vez disso, executo o seguinte comando

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

Eu só tive que resolver este problema com apache2, e lutou com o uso CustomLog para tentar redirecionar para /proc/1/fd/1 mas não consegui fazer isso funcionar. Na minha implementação, o apache não estava sendo executado como pid 1, entao a resposta de kolypto não funcionou como está. Abordagem de Pieter parecia atraente, então eu fundi os dois e o resultado funciona maravilhosamente:

# 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

Tecnicamente, isso mantém o apache access.log e error.log pretender stdout e stderr no que diz respeito ao coletor de log do docker, mas seria ótimo se houvesse uma maneira de separar os dois fora o recipiente, como um interruptor para docker logs isso mostraria apenas um ou outro...

Você pode ter um processo daemon usar syslog e ter um processo frontal que imprime?

Eles já estão indo para o syslog. Você pode simplesmente pegá-los de lá!

@ MichaelHampton, parece bom, mas o Docker executa um único processo que pode escrever para stdout, e isso soa como combinar dois deles?

@ qkrijger, bom ponto! Agora, se alguém tiver experiência com isso … ?