这篇文章已经一年多了,较旧的文章可能包含过时的内容。请检查从发表以来,页面中的信息是否变得不正确。

Kubernetes 1.29 中的上下文日志生成:更好的故障排除和增强的日志记录

作者Mengjiao Liu (DaoCloud), Patrick Ohly (Intel)

译者Mengjiao Liu (DaoCloud)

代表结构化日志工作组SIG Instrumentation, 我们很高兴地宣布在 Kubernetes v1.24 中引入的上下文日志记录功能现已成功迁移了两个组件(kube-scheduler 和 kube-controller-manager) 以及一些目录。该功能旨在为 Kubernetes 提供更多有用的日志以更好地进行故障排除,并帮助开发人员增强 Kubernetes。

上下文日志记录是什么?

上下文日志记录基于 go-logr API。 关键思想是调用者将一个日志生成器实例传递给库,并使用它进行日志记录而不是访问全局日志生成器。 二进制文件而不是库负责选择日志记录的实现。go-logr API 围绕结构化日志记录而设计,并支持向日志生成器提供额外信息。

这一设计可以支持某些额外的使用场景:

  • 调用者可以为日志生成器提供额外的信息:

    • WithName 添加一个 “logger” 键, 并用句点(.)将名称的各个部分串接起来作为取值
    • WithValues 添加键/值对

    当将此经过扩展的日志生成器传递到函数中,并且该函数使用它而不是全局日志生成器时, 所有日志条目中都会包含所给的额外信息,而无需修改生成日志条目的代码。 这一特点在高度并行的应用中非常有用。在这类应用中,很难辨识某操作的所有日志条目,因为不同操作的输出是交错的。

  • 运行单元测试时,日志输出可以与当前测试相关联。且当测试失败时,go test 仅显示失败测试的日志输出。 默认情况下,该输出也可能更详细,因为它不会在成功的测试中显示。测试可以并行运行,而无需交错输出。

上下文日志记录的设计决策之一是允许将日志生成器作为值附加到 context.Context 之上。 由于日志生成器封装了调用所预期的、与日志记录相关的所有元素, 因此它是 context 的一部分,而不仅仅是使用它。这一设计的一个比较实际的优点是, 许多 API 已经有一个 ctx 参数,或者可以添加一个 ctx 参数。 进而产生的额外好处还包括比如可以去掉函数内的 context.TODO() 调用。

如何使用它

从 Kubernetes v1.24 开始,上下文日志记录功能处于 Alpha 状态,因此它需要启用 ContextualLogging 特性门控。 如果你想在该功能处于 Alpha 状态时对其进行测试,则需要在 kube-controller-managerkube-scheduler 上启用此特性门控。

对于 kube-scheduler,有一点需要注意,除了启用 ContextualLogging 特性门控之外, 插桩行为还取决于日志的详细程度设置。 为了避免因 1.29 添加的上下文日志记录工具而降低调度程序的速度,请务必仔细选择何时添加额外的信息:

  • -v3 或更低日志级别中,每个调度周期仅使用一次 WithValues("pod")。 这样做可以达到预期效果,即该周期的所有日志消息都包含 Pod 信息。 一旦上下文日志记录特性到达 GA 阶段,就可以从所有日志调用中删除 “pod” 键值对。
  • -v4 或更高日志级别中,会生成更丰富的日志条目,其中 WithValues 也用于节点(如果适用),WithName 用于当前操作和插件。

下面的示例展示了这一效果:

I1113 08:43:37.029524 87144 default_binder.go:53] "Attempting to bind pod to node" logger="Bind.DefaultBinder" pod="kube-system/coredns-69cbfb9798-ms4pq" node="127.0.0.1"

这一设计的直接好处是在 logger 中可以看到操作和插件名称。podnode 已作为参数记录在 kube-scheduler 代码中的各个日志调用中。一旦 kube-scheduler 之外的其他包也支持上下文日志记录, 在这些包(例如,client-go)中也可以看到操作和插件名称。 一旦上下文日志记录特性到达 GA 阶段,就可以简化日志调用以避免重复这些值。

kube-controller-manager 中,WithName 被用来在日志中输出用户可见的控制器名称,例如:

I1113 08:43:29.284360 87141 graph_builder.go:285] "garbage controller monitor not synced: no monitors" logger="garbage-collector-controller"

logger=”garbage-collector-controller” 是由 kube-controller-manager 核心代码在实例化该控制器时添加的,会出现在其所有日志条目中——只要它所调用的代码支持上下文日志记录。 转换像 client-go 这样的共享包还需要额外的工作。

性能影响

在包中支持上下文日志记录,即接受来自调用者的记录器,成本很低。 没有观察到 kube-scheduler 的性能影响。如上所述,添加 WithNameWithValues 需要更加小心。

在 Kubernetes 1.29 中,以生产环境日志详细程度(-v3 或更低)启用上下文日志不会导致 kube-scheduler 速度出现明显的减慢, 并且 kube-controller-manager 速度也不会出现明显的减慢。在 debug 级别,考虑到生成的日志使调试更容易,某些测试用例减速 28% 仍然是合理的。 详细信息请参阅有关将该特性升级为 Beta 版的讨论

对下游用户的影响

日志输出不是 Kubernetes API 的一部分,并且经常在每个版本中都会出现更改, 无论是因为开发人员修改代码还是因为不断转换为结构化和上下文日志记录。

如果下游用户对特定日志有依赖性,他们需要了解此更改如何影响他们。

进一步阅读

如何参与

如果你有兴趣参与,我们始终欢迎新的贡献者加入我们。上下文日志记录为你参与 Kubernetes 开发做出贡献并产生有意义的影响提供了绝佳的机会。 通过加入 Structured Logging WG, 你可以积极参与 Kubernetes 的开发并做出你的第一个贡献。这是学习和参与社区并获得宝贵经验的好方法。

我们鼓励你探索存储库并熟悉正在进行的讨论和项目。这是一个协作环境,你可以在这里交流想法、提出问题并与其他贡献者一起工作。

如果你有任何疑问或需要指导,请随时与我们联系,你可以通过我们的公共 Slack 频道联系我们。 如果你尚未加入 Slack 工作区,可以访问 https://slack.k8s.io/ 获取邀请。

我们要向所有提供精彩评论、分享宝贵见解并协助实施此功能的贡献者表示感谢(按字母顺序排列):