如何使用docker在微服务架构中发布日志?

Heroku将其十二因子应用程序清单中的日志描述为简单的事件stream:

日志是从所有正在运行的进程和后台服务的输出stream中收集的聚合的,按时间sorting的事件stream。 login他们的原始forms通常是一个文本格式,每行一个事件(尽pipe从例外的回溯可能跨越多行)。 日志没有固定的开始或结束,但只要应用程序正在运行,就会持续stream动。

此外,应用程序应该简单地将日志写入stdout ,将任务留在“环境”中。

一个十二分之一的应用程序从不关心其输出stream的路由或存储。 它不应该尝试写入或pipe理日志文件。 相反,每个正在运行的进程都将其未缓冲的事件stream写入stdout。 在本地开发期间,开发人员将在terminal的前台查看此stream,观察应用程序的行为。

在部署或生产部署中,每个进程的stream将被执行环境捕获,与来自应用程序的所有其他stream进行整理,并发送到一个或多个最终目的地进行查看和长期归档。 这些归档目标对应用程序不可见或不可configuration,而是由执行环境完全pipe理。 开源日志路由器(如Logplex和Fluent)可用于此目的。

那么在docker环境中,在可靠性,效率和易用性方面达到这个目标的最好方法是什么? 我想下面的问题是想到的:

  • 依靠Docker自己的日志工具( docker logs )是否安全?
  • 运行docker undetached并将其输出视为日志stream安全吗?
  • stdout可以直接redirect到一个文件(磁盘空间)?
  • 如果使用文件,它应该在泊坞窗图像或一个绑定的卷内( docker run --volume=[] )?
  • 是否需要login?
  • 将stdout直接redirect到一个logshipper(以及哪个logshipper)是安全的吗?
  • 命名pipe道(aka FIFO)是一个选项吗?
  • (更多问题?)

Docker 1.6 引入了日志驱动的概念,以提供对日志输出的更多控制。 --log-driver标志configuration应该在容器中运行的进程的stdoutstderr的位置。 另请参阅configurationlogging驱动程序 。

有几个驱动程序可用。 请注意,除json-file外,所有这些都禁用了docker logs来收集容器日志。

  • none – 禁用容器日志。
  • json-file – 像以前一样执行,在/var/lib/docker/containers/<containerid>/<containerid>-json.log提供了json格式的标准输出
  • syslog – 将消息写入syslog。 还接受--log-opt通过TCP,UDP或Unix域套接字将日志消息引导到指定的系统日志。 还禁用docker logs
  • journald – 写入systemd日志。
  • * gelf – Graylog扩展日志格式(GELF)。 将日志消息写入GELF端点(如Graylog或Logstash)
  • * fluentd – 发送容器日志到fluentd 。 接受一些选项来定制fluentd的地址并发送带有日志消息的标签。
  • ** awslogs – 将日志消息写入AWS CloudWatch Logs

* Docker 1.8新增function

** Docker 1.9新增function

例如:

 docker run --log-driver=syslog --log-opt syslog-address=tcp://10.0.0.10:1514 ... 

这是Docker推荐的将日志消息写入stdoutstderr软件解决scheme。 但是,某些软件不会将日志消息写入stdout/stderr 。 例如,它们会写入日志文件或syslog。 在这些情况下,以下原始答案中的一些细节仍然适用。 回顾一下:

如果应用程序写入本地日志文件,则从主机挂载一个卷(或者在容器中使用纯数据容器并将日志消息写入该位置。

如果应用程序写入syslog,有几个选项:

  • 通过使用-v /dev/log:/dev/log将主机的syslog套接字( /dev/log )挂载到容器,发送到主机的系统-v /dev/log:/dev/log
  • 如果应用程序在其configuration中接受系统日志端点,则configuration主机的系统日志守护程序以侦听Docker桥接networking上的TCP和/或UDP,并使用该端点。 或者只是发送到远程系统日志主机。
  • 在容器中运行syslog守护进程,并使用Docker链接从其他正在运行的容器中访问它。
  • 使用logspout通过UDP将容器日志自动路由到远程系统日志

不要忘记,容器中的任何日志都应该像在主机操作系统上一样进行旋转。


Docker 1.6之前的原始答案

依靠Docker自己的日志工具(docker日志)是否安全?

docker logs每次打印整个stream,而不仅仅是新的日志,所以这是不合适的。 docker logs --follow会给tail -f docker logs --follow的function,但是你有一个docker CLI命令一直运行。 因此,尽pipe运行docker logs安全的 ,但并不是最佳的。

运行docker undetached并将其输出视为日志stream安全吗?

您可以使用systemd启动容器,而不是守护进程,从而捕获systemd日志中的所有stdout,然后由主机pipe理,不过您可以根据需要进行pipe理。

stdout可以直接redirect到一个文件(磁盘空间)?

你可以用docker run ... > logfile来做到这一点,但是感觉自动化和pipe理更加脆弱和困难。

如果使用文件,它应该在泊坞窗图像或一个绑定的卷内(docker run –volume = [])?

如果在容器中写入,则需要在容器中运行logrotate或其他东西来pipe理日志文件。 最好从主机装入卷并使用主机的日志循环守护进程来控制卷。

是否需要login?

当然,如果应用程序写入日志,则需要像在本机操作系统环境中一样旋转它们。 但是由于日志文件的位置不可预测,因此在容器中写入会更困难。 如果在主机上轮换,则日志文件将位于下面,例如,使用devicemapper作为存储驱动程序/var/lib/docker/devicemapper/mnt/<containerid>/rootfs/... 一些丑陋的包装将需要logrotatefind该路​​径下的日志。

将stdout直接redirect到一个logshipper(以及哪个logshipper)是安全的吗?

最好使用syslog,让日志收集器处理syslog。

命名pipe道(aka FIFO)是一个选项吗?

命名pipe道是不理想的,因为如果pipe道的读取端死亡,作家(容器)将得到一个破损的pipe道。 即使这个事件是由应用程序处理,它将被阻止,直到再次有读者。 另外它绕过docker logs

用docker看fluentd这篇文章 。

请参阅Jeff Lindsay的工具logspout ,该工具从正在运行的容器收集日志,然后根据需要路由它们。

最后,请注意,容器日志logging到/var/lib/docker/containers/<containerid>/<containerid>-json.log的主机上的文件。