使用边车(Sidecar)容器

本文适用于使用新的内置边车容器特性的用户。

边车容器并不是一个新概念,正如在博客文章中所提到的那样。 Kubernetes 允许在一个 Pod 中运行多个容器来实现这一概念。然而,作为一个普通容器运行边车容器存在许多限制, 这些限制通过新的内置边车容器支持得到了解决。

特性状态: Kubernetes v1.29 [beta] (enabled by default: true)

教程目标

  • 理解边车容器的需求
  • 能够排查边车容器的问题
  • 了解如何"注入"边车容器到任意的工作负载中

准备开始

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

你的 Kubernetes 服务器版本必须不低于版本 1.29. 要获知版本信息,请输入 kubectl version.

边车容器概述

边车容器是与主应用程序容器在同一 Pod 内一起运行的辅助容器。这些容器通过提供额外的服务或功能(如日志记录、监控、安全或数据同步)来增强或扩展主应用容器的功能, 而无需直接修改主应用程序代码。你可以在边车容器概念页面中阅读更多相关内容。

边车容器的概念并不新鲜,有许多不同的实现方式。除了你(定义 Pod 的人)希望运行的边车容器外, 一些插件也会在 Pod 开始运行之前对其进行修改, 以添加额外的边车容器。这些额外边车容器的注入机制通常是变更 Webhook(Mutating Webhook)。 例如,服务网格插件可能会注入一个配置双向 TLS(Mutual TLS)和传输中加密的边车容器。

虽然边车容器的概念并不新鲜,但 Kubernetes 对这一特性的原生实现却是新的。 与每一项新特性一样,采用这一特性可能会带来某些挑战。

本教程探讨了终端用户和边车容器作者可能遇到的挑战及其解决方案。

内置边车容器的优势

使用 Kubernetes 对边车容器的原生支持可以带来以下几个好处:

  1. 你可以配置原生边车容器在 Init 容器之前启动。
  2. 内置边车容器可以编写为确保它们最后终止。一旦所有常规容器完成并终止,边车容器将接收到 SIGTERM 信号。 如果边车容器未能体面关闭,系统将使用 SIGKILL 信号终止它。
  3. 在 Job 中,当 Pod 配置 restartPolicy: OnFailurerestartPolicy: Never 时, 原生边车容器不会阻止 Pod 完成。而对于传统边车容器,需要特别处理这种情况。
  4. 同样在 Job 中,即使 Pod 的 restartPolicy: Never 时常规容器不会重启, 内置边车容器仍会在完成后继续重启。

更多详情请参见与 Init 容器的区别

采用内置边车容器

从 Kubernetes 1.29 版本开始,SidecarContainers 特性门控处于 Beta 阶段, 并默认启用。某些集群可能禁用了此特性,或者安装了与该特性不兼容的软件。

当这种情况发生时,Pod 可能会被拒绝,或者边车容器可能阻止 Pod 启动,导致 Pod 无法使用。 这种情况下很容易检测到问题,因为 Pod 会卡在初始化阶段。然而,通常不清楚是什么原因导致了问题。

以下是在使用边车容器处理工作负载时可以考虑的因素和排查步骤。

确保特性门控已启用

首先,确保 API 服务器和节点都在 Kubernetes v1.29 及更高版本上运行。 如果节点运行的是早期版本且未启用该特性,集群中的该特性将无法正常工作。

你应该确保控制平面内的 API 服务器所有节点都启用了特性门控。

一种检查特性门控是否启用的方法是运行如下命令:

  • 对于 API 服务器:

    kubectl get --raw /metrics | grep kubernetes_feature_enabled | grep SidecarContainers
    
  • 对于单个节点:

    kubectl get --raw /api/v1/nodes/<node-name>/proxy/metrics | grep kubernetes_feature_enabled | grep SidecarContainers
    

如果你看到类似这样的内容:

kubernetes_feature_enabled{name="SidecarContainers",stage="BETA"} 1

表示该特性已启用。

检查第三方工具和变更 Webhook

如果你在验证特性时遇到问题,这可能表明某个第三方工具或变更 Webhook 出现了问题。

SidecarContainers 特性门控启用后,Pod 在其 API 中会新增一个字段。 某些工具或变更 Webhook 可能是基于早期版本的 Kubernetes API 构建的。

如果工具使用各种修补策略将未知字段原样传递,这不会有问题。然而,有些工具会删除未知字段; 如果你使用的是这些工具,必须使用 v1.28+ 版本的 Kubernetes API 客户端代码重新编译它们。

检查这一点的方法是使用 kubectl describe pod 命令查看已通过变更准入的 Pod。 如果任何工具删除了新字段(如 restartPolicy: Always),你将不会在命令输出中看到它。

如果你遇到了此类问题,请告知工具或 Webhook 的作者使用修补策略来修改对象,而不是进行完整的对象更新。

边车的自动注入

如果你使用的是自动注入边车的软件,可以采取几种策略来确保能够使用原生边车容器。 所有这些策略通常都是你可以选择的选项,以决定注入边车的 Pod 是否会落在支持该特性的节点上。

例如,可以参考 Istio 社区中的这次讨论。 讨论中探讨了以下选项:

  1. 标记支持边车的节点上的 Pod。你可以使用节点标签和节点亲和性来标记支持边车容器的节点以及落在这些节点上的 Pod。
  1. 注入时检查节点兼容性。在边车注入过程中,可以使用以下策略来检查节点兼容性:
    • 查询节点版本并假设版本 1.29+ 上启用了特性门控。
    • 查询节点 Prometheus 指标并检查特性启用状态。
    • 假设节点与 API 服务器的版本差异在支持的版本范围内。
    • 可能还有其他自定义方法来检测节点兼容性。
  1. 开发通用边车注入器(Sidecar Injector)。通用边车注入器的想法是在注入一个普通容器的同时注入一个原生边车容器,并在运行时决定哪个容器会生效。 通用边车注入器虽然浪费资源(因为它会两次计算请求量),但在某些特殊情况下可以视为可行的解决方案。
    • 一种方法是在原生边车容器启动时检测节点版本,如果不支持边车特性则立即退出。
    • 考虑运行时特性检测设计:
      • 定义一个空目录(Empty Dir)以便容器之间通信。
      • 注入一个 Init 容器,我们称之为 NativeSidecar,并设置 restartPolicy=Always
      • NativeSidecar 必须在空目录中写入一个文件,表示首次运行并立即退出,退出码为 0
       - `NativeSidecar` 在重启时(当支持原生边车时)检查空目录中是否已存在该文件,并进行更改 —— 表示已支持原生边车容器并正在运行。
      
      • 注入一个普通容器,我们称之为 OldWaySidecar
      • OldWaySidecar 启动时检查空目录中是否存在文件。
      • 如果文件表示 NativeSidecar 未运行,则假设边特性不支持,并按边车的方式工作。
      • 如果文件表示 NativeSidecar 正在运行,则根据 Pod 的 restartPolicy 决定行为:
      • 如果 Pod 的 restartPolicy=Always,则不做任何操作并永远休眠。
      • 如果 Pod 的 restartPolicy!=Always,则立即退出,退出码为 0

接下来

最后修改 November 09, 2024 at 4:01 PM PST: [zh-cn]sync pod-sidecar-containers.md (4af7215d08)