让 Docker 应用程序写入 stdout

让 Docker 应用程序写入 stdout

我正在部署符合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 

相关内容