从多进程 docker 容器记录
Logging from multiprocess docker containers
我正在使用符号链接的 nginx 方法链接到 /dev/stdout 用于我想出现在 'docker logs' 中的任何日志文件,但是这不起作用。
我已经在 /etc/crontab 中用一个简单的 cronjob 测试了这个,如果存在符号链接(指向 /dev/stdout)它不会写任何东西(据我所知),但是如果我删除符号链接并将其写入文件。
此外,如果我回显到 /dev/stdout,它会在命令行中回显,但是在 'docker logs'...
中找不到
问题:这应该有效吗? (它似乎适用于 nginx)。否则,我如何从 'secondary' 进程中获取日志以显示在 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
好吧,评论中提到了,但仅供参考 - 我发现 docker
日志记录的最佳解决方案通常依赖于 'standard' multi-system 日志记录机制 - 特别是 syslog
尽可能。
这是因为您可以在主机上使用内置的 syslogd,或者使用 logstash 作为 syslogd。它有一个内置的过滤器,但实际上它往往会因为不够灵活而受到一些影响,所以我使用 TCP/UDP 侦听器,并显式解析日志 - 如 "When logstash and syslog goes wrong"[=28= 中所述]
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 - 在远程主机、本地容器上或者我现在正在做的是 docker network
和 multi-node elasticsearch 实例。 (我已经使用下载和 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
设置稍微复杂一些,因为您需要设置一个 key-value 商店(我使用 etcd
但其他选项可用)。或者你可以做一些像 Kubernetes 这样的事情。
然后使用 kibana
进行可视化,再次公开 kibana 端口,但转发到 elasticsearch 网络以与集群通信。
但是一旦设置完成,您就可以将 nginx
配置为 log to syslog
,以及您希望定期捕获日志记录结果的任何其他内容。 IMO 的真正优势在于您使用单一服务进行日志记录,该服务可以根据您的需要进行扩展(感谢 networking/containerisation)。
最终结果是 cron 作业的 /dev/stdout 指向不同的设备。
/proc/self/fd/1 应该是 /proc/1/fd/1 因为 docker 只希望一个进程是 运行 这是它监视的唯一标准输出。
因此,一旦我修改了符号链接以指向 /proc/1/fd/1,它应该可以工作,但是 apparmor(在主机上)实际上拒绝了请求(并且在回显到 /proc/1/fd/1 时出现权限错误)因为默认的 docker 配置文件(它是自动生成的,但可以用 --security-opts 修改)。
一旦越过装备障碍,一切正常!
这就是说,在查看了 apparmor 中需要修改的内容以允许所需的请求之后,我决定使用 mkfifo 方法,如下所示。
Docker 文件
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
我正在使用符号链接的 nginx 方法链接到 /dev/stdout 用于我想出现在 'docker logs' 中的任何日志文件,但是这不起作用。
我已经在 /etc/crontab 中用一个简单的 cronjob 测试了这个,如果存在符号链接(指向 /dev/stdout)它不会写任何东西(据我所知),但是如果我删除符号链接并将其写入文件。
此外,如果我回显到 /dev/stdout,它会在命令行中回显,但是在 'docker logs'...
中找不到问题:这应该有效吗? (它似乎适用于 nginx)。否则,我如何从 'secondary' 进程中获取日志以显示在 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
好吧,评论中提到了,但仅供参考 - 我发现 docker
日志记录的最佳解决方案通常依赖于 'standard' multi-system 日志记录机制 - 特别是 syslog
尽可能。
这是因为您可以在主机上使用内置的 syslogd,或者使用 logstash 作为 syslogd。它有一个内置的过滤器,但实际上它往往会因为不够灵活而受到一些影响,所以我使用 TCP/UDP 侦听器,并显式解析日志 - 如 "When logstash and syslog goes wrong"[=28= 中所述]
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 - 在远程主机、本地容器上或者我现在正在做的是 docker network
和 multi-node elasticsearch 实例。 (我已经使用下载和 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
设置稍微复杂一些,因为您需要设置一个 key-value 商店(我使用 etcd
但其他选项可用)。或者你可以做一些像 Kubernetes 这样的事情。
然后使用 kibana
进行可视化,再次公开 kibana 端口,但转发到 elasticsearch 网络以与集群通信。
但是一旦设置完成,您就可以将 nginx
配置为 log to syslog
,以及您希望定期捕获日志记录结果的任何其他内容。 IMO 的真正优势在于您使用单一服务进行日志记录,该服务可以根据您的需要进行扩展(感谢 networking/containerisation)。
最终结果是 cron 作业的 /dev/stdout 指向不同的设备。
/proc/self/fd/1 应该是 /proc/1/fd/1 因为 docker 只希望一个进程是 运行 这是它监视的唯一标准输出。
因此,一旦我修改了符号链接以指向 /proc/1/fd/1,它应该可以工作,但是 apparmor(在主机上)实际上拒绝了请求(并且在回显到 /proc/1/fd/1 时出现权限错误)因为默认的 docker 配置文件(它是自动生成的,但可以用 --security-opts 修改)。
一旦越过装备障碍,一切正常!
这就是说,在查看了 apparmor 中需要修改的内容以允许所需的请求之后,我决定使用 mkfifo 方法,如下所示。
Docker 文件
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