从多进程docker容器中记录

时间:2016-01-22 15:41:10

标签: logging nginx process docker

我正在使用符号链接到/ dev / stdout的nginx方法来查找我想在“docker logs”中显示的任何日志文件,但是这不起作用。

我在/ etc / crontab中用一个简单的cronjob测试了这个,如果存在符号链接(指向/ dev / stdout)它不写任何东西(据我所知),但是如果我删除了符号链接,它写入文件。

此外,如果我回显到/ dev / stdout,它会在命令行上回显但是在“docker logs”中找不到...

问题:这应该有效吗? (它似乎适用于nginx)。否则,我如何从“辅助”进程中获取日志以显示在docker日志中。

对于参考:

显示符号链接方法的Nginx Dockerfile:https://github.com/nginxinc/docker-nginx/blob/a8b6da8425c4a41a5dedb1fb52e429232a55ad41/Dockerfile

为此创建了一个官方错误报告:https://github.com/docker/docker/issues/19616

我的Dockerfile:

FROM ubuntu:trusty
#FROM quay.io/letsencrypt/letsencrypt:latest # For testing

ENV v="Fri Jan 22 10:08:39 EST 2016"

# Setup the cronjob
ADD crontab /etc/crontab
RUN chmod 600 /etc/crontab

# Setup letsencrypt logs
RUN ln -sf /dev/stdout /var/log/letsencrypt.log
# Setup cron logs
RUN ln -sf /dev/stdout /var/log/cron.log
RUN ln -sf /dev/stdout /var/log/syslog

# Setup keepalive script
ADD keepalive.sh /usr/bin/keepalive.sh
RUN chmod +x /usr/bin/keepalive.sh

ENTRYPOINT /usr/bin/keepalive.sh

crontab文件:

* * * * * root date >> /var/log/letsencrypt.log

keepalive.sh脚本

#!/bin/bash

# Start cron
rsyslogd
cron

echo "Keepalive script running!"

while true; do

    echo 'Sleeping for an hour...'
    sleep 10

done

2 个答案:

答案 0 :(得分:3)

嗯,评论中提到过,但供参考 - 我发现docker日志记录的最佳解决方案通常依赖于'标准'多系统日志记录机制 - 尽可能syslog

这是因为您可以在主机上使用内置的syslogd,也可以使用logstash作为syslogd。它有一个内置的过滤器,但实际上往往会因为不够灵活而受到一点影响,所以我使用TCP / UDP监听器,并明确地解析日志 - 如"When logstash and syslog goes wrong"中所述

input {
  tcp {
    port => 514
    type => syslog
  }
  udp {
    port => 514
    type => syslog
  }
}

然后过滤日志:

filter {
  if [type] == "syslog" {
    grok {
      match => { "message" => "<%{POSINT:syslog_pri}>%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
    }
    syslog_pri { }
  }
}

然后,您可以将此logstash提供给elasticsearch - 在远程主机上,本地容器或我现在正在做的是具有多节点elasticsearch实例的docker network。 (我已经使用下载和docker文件自行推出了自己的文件,但我非常确定还有一个独立的容器)。

output { 
   elasticsearch {
      hosts => [ "es-tgt" ]
   }
}

这里的优点是 - docker允许您使用--link--net来指定elasticsearch容器的名称,因此您可以将logstash配置别名指向正确的位置。 (例如docker run -d --link my_es_container_name:es-tgt -p 514:514 -p 514:514/udp mylogstash或仅docker run --net es_net ....

docker network设置稍微复杂一点,因为您需要设置键值存储(我使用etcd但其他选项可用)。或者你可以做像Kubernetes这样的事情。

然后使用kibana进行可视化,再次暴露kibana端口,但转发到elasticsearch网络以与群集通信。

但是一旦设置完毕,您可以将nginx配置为log to syslog,以及您希望定期捕获日志记录结果的任何其他内容。 IMO的真正优势在于您使用单一服务进行日志记录,可以根据您的需要对其进行扩展(由于网络/容器化)。

答案 1 :(得分:3)

最终结果是cron作业的/ dev / stdout指向不同的设备。

/ proc / self / fd / 1并且应该是/ proc / 1 / fd / 1,因为docker只希望一个进程运行,这是它监视的唯一stdout。

所以,一旦我修改了符号链接指向/ proc / 1 / fd / 1它应该有效但是apparmor(在主机上)实际上是在拒绝请求(并在回显到/ proc / 1 /时获得权限错误fd / 1)因为默认的docker配置文件(自动生成但可以使用--security-opts修改)。

一旦超过apparmor障碍,一切正常!

这就是说,在查看apparmor中需要修改的内容以允许所需的请求后,我决定使用mkfifo方法,如下所示。

Dockerfile

FROM ubuntu:latest

ENV v="RAND-4123"

# Run the wrapper script (to keep the container alive)
ADD daemon.sh /usr/bin/daemon.sh
RUN chmod +x /usr/bin/daemon.sh

# Create the pseudo log file to point to stdout
RUN mkfifo /var/log/stdout
RUN mkfifo /var/log/stderr

# Create a cronjob to echo into the logfile just created
RUN echo '* * * * * root date 2>/var/log/stderr 1>/var/log/stdout' > /etc/crontab

CMD "/usr/bin/daemon.sh"

daemon.sh

#!/bin/bash

# Start cron
cron

tail -qf --follow=name --retry /var/log/stdout /var/log/stderr