使一个Docker应用程序写入标准输出

我正在部署第三方应用程序,以符合12个因素的build议 ,其中一个要点说明应将应用程序日志打印到stdout / stderr:然后集群软件可以收集它。

但是,应用程序只能写入文件或系统日志。 我如何打印这些日志呢?

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 

简单地说,应用程序可以继续将其作为文件写入,但是作为结果,这些行会转到stdoutstderr

另一个问题是, 当父母离开时杀死孩子的过程 ,我得到了帮助解决这个问题的答案。

这样,我们configuration应用程序,使其logging到一个文件,并不断tail -f 。 幸运的是, tail可以接受--pid PID :当指定的进程退出时它会退出。 我们把$$放在那里:当前shell的PID。

作为最后一步,已启动的应用程序将被exec ,这意味着当前的shell已被完全replace为该应用程序。

Runner脚本, run.sh ,将如下所示:

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

注意:通过使用tail -F我们列出文件名,即使它们稍后出现,它也会读取它们!

最后,简单的Dockerfile:

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

注意:为了解决一些非常奇怪的tail -f行为(说“已经被replace为远程文件,放弃这个名字”),我尝试了另一种方法:所有已知的日志文件都是在启动时创build和截断的:确保它们存在,只有这样 – 尾巴:

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

对于nginx,你可以像这样将nginx.conf指向/dev/stderr/dev/stdout

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

和你的Dockerfile条目应该是

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