【问题标题】:redirect log files created in a docker container to stdout / stderr将 docker 容器中创建的日志文件重定向到 stdout / stderr
【发布时间】:2021-02-26 00:08:14
【问题描述】:

我有以下 Dockerfile:

FROM ubuntu:16.04
RUN apt-get update
VOLUME ["/LOGS"]
COPY ./testServer .
ENTRYPOINT ./testServer 8600

“testServer”有正在写入的日志文件。它们位于目录“LOGS”中。每次启动“testServer”时,都会创建一个新日志。我想做的是将目录中的最新日志文件“尾”到stdout/stderr。

我尝试添加:

CMD ["/bin/sh", "-c", "tail $( ls -Art /LOGS | tail -n 1 ) > out_server.log 2>&1"]

到 Dockerfile(然后重建映像),但它不起作用。

如何做到这一点?

TIA

【问题讨论】:

  • 您希望输出到文件 out_server.log 还是到 stdout?当你说它不起作用时,它做错了什么?
  • 你可以使用docker exec container_name -c "tail -f /your/path/to/log"
  • 你试过docker logs吗?
  • 大家好,感谢您的回复
  • @BMitch - 我希望输出到标准输出/标准错误。我正在使用 Portainer - 它 (Portainer) 允许查看正在运行的容器的 stderr 和 stdout 文件。当我将 CMD(上图)放入 Dockerfile(并创建一个新图像)时,在运行它时,Portainer 在 stderr/stdout 显示中没有显示任何内容。

标签: docker stdout stderr


【解决方案1】:

您可以将日志文件符号链接到容器进程的标准输出,而不是使用 tail。为此,您需要将可执行文件包装在单独的脚本中,以便将其作为与容器主进程分开的进程启动。

要执行的脚本:

#!/bin/bash

# The application log will be redirected to the main docker container process's stdout, so # that it will show up in the container logs
touch /my/app/application.log
ln -sf /proc/1/fd/1 /my/app/application.log

# Execute my app
./testServer 8600

然后在 docker 文件中复制并执行脚本

COPY start_server.sh /the/above/script/start_server.sh
CMD ["/bin/bash", "/the/above/script/start_server.sh"]

【讨论】:

  • 我非常喜欢这个解决方案。我担心处理日志轮换,但在一个临时容器中,我可以不用担心它。我将在这里添加的几个小附录是,我不知道您为什么要先触摸文件,无论如何 ln -sf 都应该创建它。而且,我没有打扰包装脚本,只是在 Dockerfile 中创建了符号链接。
  • 大多数容器可能只有一个进程在里面运行,但是我们不会因此丢失其他进程写入stdout的数据吗?
  • 本质上与 Ganapathi 相同的问题。这不会使其日志文件本质上是标准输出,并且要么:阻止通常写入 STDOUT 的任何内容写入那里,或者导致尝试写入 STDOUT 的内容实际写入日志文件?
【解决方案2】:

这里有两个问题。

  1. 您定义了ENTRYPOINT,并尝试使用CMD 运行命令。 Docker 使用单个进程启动一个容器,当您同时定义这两个进程时,CMD 将作为附加的 cli 参数附加到ENTRYPOINT。容器作为 pid 1 运行的是:

    /bin/sh -c './testServer 8600 /bin/sh -c "tail $( ls -Art /LOGS | tail -n 1 ) > out_server.log 2>&1"'

    除非 testServer 运行额外的参数,否则它们永远不会被使用。

  2. 1234563如果那是您的 pid 1,则容器也会在此时退出。

要解决此问题,您可以创建一个 entrypoint.sh,如下所示:

#!/bin/sh

./testServer 8600 &
sleep 2 # give testServer time to create the newest log
exec tail -f $( ls -Art /LOGS | tail -n 1 )

该入口点在后台启动 testServer,然后使用 exec 运行尾部。 exec 替换 pid 1 以便信号通过。

将您的 Dockerfile 更新为:

FROM ubuntu:16.04

# This apt-get line shouldn't be needed unless something else 
# needs the possibly outdated package repo list
# RUN apt-get update

# Removing this volume, you can create it from a docker-compose.yml
# VOLUME ["/LOGS"]

COPY entrypoint.sh testServer /
RUN chmod 755 /entrypoint.sh /testServer
ENTRYPOINT [ "/entrypoint.sh" ]

有关我删除VOLUME 行的原因的更多详细信息,请参阅my blog post here

【讨论】:

    【解决方案3】:

    我发现以下有用。

    #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
    

    由于以上几行,写入access.logerror.log 的内容将分别写入stdoutstderr

    Source

    【讨论】:

      【解决方案4】:

      如果这是一个要求,我会重新配置 ubuntu 用来输出的系统日志。一个例子是here

      【讨论】:

      • 谢谢 - 我只是想将日志文件的内容(服务器正在写入的)重定向到容器本身的 stdout/stderr。 Portainer 软件显示正在运行的容器的标准错误/标准输出。
      猜你喜欢
      • 2014-07-22
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      相关资源
      最近更新 更多