为 rsyslog 启用输出到 stdout/journald 的日志记录

https://blueprints.launchpad.net/tripleo/+spec/logging-stdout-rsyslog

我们可以优化当前的日志记录实现,以利用默认日志驱动程序 (journald) 添加到日志中的元数据。

问题描述

目前,我们将所有容器的日志放入主机中的一个目录 (/var/log/containers/)。虽然这种方法有效,但它依赖于从主机本身挂载目录。这使得日志转发器更难配置,因为我们需要配置它们来跟踪所有这些文件。随着我们添加的每个服务,我们最终都需要为这些特定文件编写该服务的配置。

此外,使用这种方法我们会丢失重要的元数据。我们可以确定哪个服务写入了哪个日志,但我们会丢失容器名称和 ID,这非常有用。我们可以仅通过使用默认的 docker 日志记录机制轻松获得这些信息。

与其依赖主机文件系统来记录我们的日志,我们可以采用更简单的解决方案,该解决方案既能保留当前实现丢弃的重要元数据,又能支持大多数服务而无需为每个服务配置。

提议的变更

概述

建议将容器化服务配置为记录到 stdout/stderr,这对于容器化应用程序来说是一种常见做法。这允许日志被 docker 日志驱动程序拾取,因此我们可以使用“docker logs”来查看服务的日志,就像通常期望的那样。它还将帮助我们将容器与主机解耦,因为我们将不再依赖主机文件系统挂载来进行日志收集。

对于难以或不可能记录到 stdout 或 stderr 的服务,我们将把日志文件放在一个 docker 卷中,并且该卷将与一个 sidecar 容器共享,该 sidecar 容器会将日志输出到 stdout,以便日志驱动程序可以消费。这同样适用于仅记录到 syslog 的容器(例如 HAProxy)。我们将停止从主机挂载 /dev/log,而是添加一个 sidecar 容器,该容器将输出日志。

此外,由于我们的默认日志驱动程序是 journald,我们将获得所有容器日志,这些日志可以通过 journalctl 和 journald 库访问。因此,人们可以执行 journalctl CONTAINER_NAME=<container name> 来获取节点上特定容器的日志。此外,我们将为每个日志条目获得额外的元数据信息 [1]。我们可以从每个 journald 日志条目中获得容器名称(作为 CONTAINER_NAME 元数据项)和容器 ID(作为 CONTAINER_IDCONTAINER_ID_FULL 元数据项),而无需额外的处理。可以向容器添加额外的标签 [2],这些标签将通过 CONTAINER_TAG 元数据条目反映出来。这些标签可以可选地描述发出日志的应用程序或描述其来源的平台。

这还将使我们更容易转发日志,因为每个主机上都将有一个集中式服务 (journald),我们可以从中收集日志。当我们添加新服务时,只需遵循相同的日志记录模式,我们就可以自动转发这些日志,而无需特定的配置来跟踪一组新的日志文件。

有了这个解决方案,我们还需要提供与集中式日志记录解决方案集成的工具。这将涵盖与 Openshift Logging Stack [3] 和 ViaQ [4] 的集成。我们建议使用 rsyslog 进行消息收集、操作和日志转发。这也将在容器化的方式下完成,rsyslog 将是一个“系统容器”,从主机 journal 读取。Rsyslog 将从日志消息中执行元数据提取(例如从标准 oslo 格式日志中提取用户、项目和域),然后最终将日志转发到中央收集器。

可插拔实现

该实现需要以可插拔的方式完成。这是因为最终用户已经基于日志存在于我们提供的 /var/log/<service> / /var/log/containers/* 目录中的假设创建了自动化。因此,记录到 stdout/stderr 将是可选的,并且我们现在将继续默认将日志记录到主机中的文件。然后可以通过环境变量选择性地启用它。

示例

nova-api 容器

在建议的解决方案中,标准的 nova 日志将进入 nova_api 容器的 stdout/stderr。但是,由于我们还对 apache 访问日志感兴趣,因此我们将创建一个 docker 卷,其中将托管访问日志。一个 sidecar 容器将挂载此卷,创建一个 FIFO(命名管道),并输出从该文件获取的任何内容。请注意,此 sidecar 容器需要在实际的 nova_api 容器之前启动。

对于在主容器中生成的每个日志文件,我们将创建一个输出该日志的 sidecar 容器。这将更容易将日志消息与源服务关联起来。

替代方案

继续将日志记录到主机目录中的文件。

我们仍然可以使用当前的解决方案;但是,它不是理想的,因为它违反了容器日志记录的最佳实践,严重依赖主机上的目录(我们希望避免),并且在我们可以从服务中获取日志记录的方式上不一致(有些在文件中,有些在 syslog 中)。

其他最终用户影响

由于我们没有取消之前的日志记录解决方案,用户不会受到影响。但是,他们将获得另一种获取日志记录并与之交互的方式,并根据需要进一步创建自动化。

性能影响

  • TODO:将所有内容获取到 journald 的性能考虑因素?

实现

主要负责人

jaosorior jbadiapa larsks

工作项

  • 允许服务记录到 stdout/stderr(如果可能)。

  • 在 t-h-t 中为每个服务实现可插拔的日志记录。

  • 添加 Rsyslog 容器。

测试

TODO:评估我们如何在 upstream CI 中记录到 EFK 堆栈。我们有可用的吗?

参考资料

[1] https://docs.container.net.cn/engine/admin/logging/journald/ [2] https://docs.container.net.cn/engine/admin/logging/log_tags/ [3] https://docs.openshift.org.cn/container-platform/3.5/install_config/aggregate_logging.html [4] https://github.com/ViaQ/Main/blob/master/README-install.md