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

时间:2014-07-17 15:20:11

标签: logging soa docker

Heroku将其Twelve-Factor App manifest中的日志描述为简单的事件流:

  

日志是从所有正在运行的进程和支持服务的输出流中收集的聚合的,按时间排序的事件流。原始格式的日志通常是文本格式,每行一个事件(尽管异常的回溯可能跨越多行)。日志没有固定的开头或结尾,但只要应用正在运行,就会持续流动。

此外,应用只需将日志写入stdout,将任务留给"环境"。

  

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

     

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

那么在可靠性,效率和易用性方面,在docker环境中实现这一目标的最佳方法是什么?我想到了以下问题:

  • 依赖Docker自己的日志工具(docker logs)是否安全?
  • 运行未分离的docker并将其输出视为日志记录流是否安全?
  • 可以stdout直接重定向到文件(磁盘空间)吗?
  • 如果使用文件,是应该在docker镜像内还是在绑定卷(docker run --volume=[])内?
  • 是否需要进行logrotation?
  • 将stdout直接重定向到logshipper(以及哪个logshipper)是否安全?
  • 命名管道(又名FIFO)是一个选项吗?
  • (更多问题?)

1 个答案:

答案 0 :(得分:28)

Docker 1.6 introduced logging drivers的概念,提供对日志输出的更多控制。 --log-driver标记配置stdout&应该指示来自容器中运行的进程的stderr。另请参阅Configuring Logging drivers

有几个司机可用。请注意,除json-file之外的所有这些都禁止使用docker logs来收集容器日志。

  • none - 禁用容器日志。
  • json-file - 与之前的行为一样,/var/lib/docker/containers/<containerid>/<containerid>-json.log
  • 中提供了json格式的stdout
  • syslog - 将消息写入syslog。还接受--log-opt以通过TCP,UDP或Unix域套接字将日志消息定向到指定的syslog。同时禁用docker logs
  • journald - 写入systemd期刊。
  • * gelf - Graylog扩展日志格式(GELF)。将日志消息写入GELF端点,例如Graylog或Logstash
  • *流利 - 将容器日志发送到fluentd。接受一些选项来自定义流利的地址和发送带有日志消息的标签。
  • ** awslogs - 将日志消息写入AWS CloudWatch Logs

* Docker 1.8中的新功能

** Docker 1.9中的新功能

例如:

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

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

如果应用程序写入本地日志文件,请从主机安装卷(或使用data-only container到容器并将日志消息写入该位置。

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

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

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


Docker pre-1.6

的原始答案
  

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

docker logs每次打印整个流,而不仅仅是新日志,因此它不合适。 docker logs --follow将提供tail -f - 类似功能,但随后您将一直运行docker CLI命令。因此,虽然运行docker logs 安全,但它并不是最佳的。

  

运行未缓存的docker并将其输出视为日志记录流是否安全?

您可以使用systemd而不是daemonize启动容器,从而捕获systemd日志中的所有stdout,然后可以由您自己管理的主机管理。

  

stdout可以直接重定向到文件(磁盘空间)吗?

当然,您可以使用docker run ... > logfile执行此操作,但它会感觉更脆弱,更难以自动化和管理。

  

如果使用文件,它应该在docker镜像内还是在绑定卷内(docker run --volume = [])?

如果您在容器内写入,那么您需要在容器中运行logrotate或其他东西来管理日志文件。最好从主机安装卷并使用主机的日志轮转守护程序控制它。

  

需要进行logrotation吗?

当然,如果应用程序写入日志,您需要像在本机OS环境中一样旋转它们。但是如果您在容器内部写入,则更难,因为日志文件位置不可预测。如果在主机上轮换,则日志文件将存在,例如使用devicemapper作为存储驱动程序/var/lib/docker/devicemapper/mnt/<containerid>/rootfs/...。需要一些丑陋的包装才能让logrotate在该路径下找到日志。

  

将stdout直接重定向到logshipper(以及哪个logshipper)是否安全?

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

  

命名管道(又称FIFO)是一个选项吗?

命名管道并不理想,因为如果管道的读取端死亡,编写器(容器)将会出现断管。即使该事件由应用程序处理,它也会被阻止,直到再次有读者。另外,它绕过了docker logs

另见post on fluentd with docker

请参阅Jeff Lindsay的工具logspout,该工具从正在运行的容器中收集日志并根据需要对其进行路由。

最后,请注意容器中的stdout会在/var/lib/docker/containers/<containerid>/<containerid>-json.log中记录到主机上的文件。