我正在部署符合12 因素咨询,其中一点告诉应用程序日志应该打印到 stdout/stderr:然后集群软件可以收集它。
但是,应用程序只能写入文件或系统日志。我该如何打印这些日志呢?
答案1
一个惊人的食谱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
简单来说,应用程序可以继续将其作为文件写入,但结果是行将转到stdout
& stderr
!
答案2
对于docker容器中的后台进程,例如使用exec连接到/bin/bash,我可以使用。
echo "test log1" >> /proc/1/fd/1
这会将输出发送到 pid 1 的标准输出,这是 docker 拾取并记录的一个。
答案3
在另一个问题中,当父进程退出时终止子进程,我得到了有助于解决此问题的回复。
这样,我们配置应用程序,使其记录到文件中,并持续tail -f
记录。幸运的是,tail
可以接受--pid PID
:当指定进程退出时,它将退出。我们$$
在那里放:当前 shell 的 PID。
最后一步是启动应用程序exec
,这意味着当前 shell 已完全被该应用程序替换。
运行脚本,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
行为(它说“已被替换为远程文件。放弃这个名字”),我尝试了另一种方法:所有已知的日志文件都在启动时创建和截断:这样我就可以确保它们存在,然后才 - 跟踪它们:
#! /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
答案4
在我的情况下,创建到 stdout 的符号链接不起作用,因此我运行以下命令
ln -sf /proc/self/fd/1 /var/log/main.log