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

Posted

技术标签:

【中文标题】如何使用 docker 在微服务架构中发送日志?【英文标题】:How to ship logs in a microservice architecture with docker? 【发布时间】:2014-09-08 13:29:09 【问题描述】:

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

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

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

十二因素应用程序从不关心其输出流的路由或存储。它不应尝试写入或管理日志文件。相反,每个正在运行的进程都将其事件流(无缓冲)写入标准输出。在本地开发过程中,开发者将在终端的前台查看此流,以观察应用的行为。

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

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

依赖 Docker 自己的日志工具 (docker logs) 是否安全? 独立运行 docker 并将其输出视为日志流是否安全? stdout 可以直接重定向到文件(磁盘空间)吗? 如果使用文件,它应该位于 docker 映像内还是绑定卷中 (docker run --volume=[])? 是否需要对数旋转? 将 stdout 直接重定向到 logshipper(以及哪个 logshipper)是否安全? 命名管道(又名 FIFO)是一种选择吗? (更多问题?)

【问题讨论】:

【参考方案1】:

Docker 1.6 introduced logging drivers 的概念提供对日志输出的更多控制。 --log-driver 标志配置应将容器中运行的进程中的 stdoutstderr 定向到何处。另见Configuring Logging drivers。

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

无 - 禁用容器日志。 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 中的新功能

** Docker 1.9 中的新功能

例如:

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

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

如果应用写入本地日志文件,则从主机挂载一个卷(或使用data-only container 到容器并将日志消息写入该位置。

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

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

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


Docker pre-1.6 的原始答案

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

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

独立运行 docker 并将其输出视为日志流是否安全?

您可以使用 systemd 启动容器而不是守护进程,从而捕获 systemd 日志中的所有标准输出,然后主机可以随意管理这些标准输出。

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

当然,您可以使用 docker run ... > logfile 来做到这一点,但它感觉很脆弱,而且难以自动化和管理。

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

如果您在容器内写入,则需要在容器中运行 logrotate 或其他东西来管理日志文件。最好从主机挂载一个卷并使用主机的日志轮换守护进程对其进行控制。

需要对数旋转吗?

当然,如果应用程序写入日志,您需要像在本机操作系统环境中一样轮换它们。但是,如果您在容器内写入会更难,因为日志文件的位置不可预测。如果您在主机上轮换,日志文件将存在于,例如,使用 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,该工具从正在运行的容器收集日志并根据需要路由它们。

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

【讨论】:

注意还有这个技术:使用来自另一个容器的 syslog 守护进程:jpetazzo.github.io/2014/08/24/syslog-docker 配置日志记录驱动程序链接已损坏。应该是:docs.docker.com/engine/admin/logging/overview

以上是关于如何使用 docker 在微服务架构中发送日志?的主要内容,如果未能解决你的问题,请参考以下文章

docker查看日志命令

docker入门

如何查看docker日志 怎样查看docker日志

如何查看docker日志 怎样查看docker日志

什么是Docker

centos7下安装docker(18docker日志---docker logs)