采用边车容器
本节内容适用于那些为其工作负载采用新的内置边车容器功能的人员。
正如博客文章中所提到的,边车容器并不是一个新概念。Kubernetes 允许在一个 Pod 中运行多个容器来实现这一概念。然而,将边车容器作为普通容器运行存在诸多限制,而新的内置边车容器支持功能正在解决这些问题。
目标
- 理解使用边车容器的必要性。
- 能够排查边车容器出现的问题。
- 了解将边车容器普遍 “注入” 到任何工作负载中的可选方法。
开始之前
你需要拥有一个 Kubernetes 集群,并且必须配置好kubectl命令行工具,使其能够与你的集群进行通信。建议在至少有两个非控制平面节点的集群上运行本教程。如果你还没有集群,可以使用 Minikube 创建一个,或者使用以下 Kubernetes 在线实验环境之一:
- Killercoda
- KodeKloud
- Play with Kubernetes 你的 Kubernetes 服务器版本必须为 1.29 或更高版本。
要查看版本,输入kubectl version。
边车容器概述
边车容器是与同一 Pod 内的主应用程序容器一起运行的辅助容器。这些容器用于通过提供额外的服务或功能(如日志记录、监控、安全或数据同步)来增强或扩展主应用容器的功能,而无需直接修改主应用程序代码。你可以在边车容器概念页面中了解更多信息。
边车容器的概念并不新鲜,并且有多种实现方式。除了你(定义 Pod 的人)想要运行的边车容器外,你还会发现一些插件会在 Pod 开始运行之前对其进行修改,从而添加额外的边车容器。注入这些额外边车容器的机制通常是变异 Webhook。例如,服务网格插件可能会注入一个边车容器,用于配置不同 Pod 之间的相互 TLS 和传输加密。
虽然边车容器的概念并不新鲜,但 Kubernetes 中对这一功能的原生实现却是新的。与每一个新功能一样,采用这一功能可能会带来一些挑战。
本教程将探讨终端用户以及边车容器开发者可能遇到的挑战和解决方案。
内置边车容器的优点
使用 Kubernetes 对边车容器的原生支持有以下几个优点:
启动顺序优势:可以将原生边车容器配置为在初始化容器之前启动。
终止顺序保障:内置边车容器可确保最后终止。当所有常规容器完成并终止后,边车容器会收到 SIGTERM 信号进行终止。如果边车容器未能正常关闭,将使用 SIGKILL 信号来终止它。
与 Job 配合更优:对于 Job,当 Pod 的restartPolicy为OnFailure或Never时,原生边车容器不会阻止 Pod 完成。而对于传统边车容器,处理这种情况则需要特别注意。
Job 中的重启特性:同样在 Job 中,即使 Pod 的restartPolicy为Never,内置边车容器在完成后也会继续重启,而常规容器则不会。
如需了解更多信息,请查看与初始化容器的区别。
采用内置边车容器
从 Kubernetes 1.29 版本开始,SidecarContainers 功能门控处于 beta 状态,且默认启用。但有些集群可能会禁用此功能,或者安装了与该功能不兼容的软件。
出现这种情况时,Pod 可能会被拒绝,或者边车容器可能会阻塞 Pod 的启动,导致 Pod 无法使用。这种情况很容易检测到,因为 Pod 会在初始化阶段卡住。然而,通常很难确定问题的原因。
在为工作负载采用边车容器时,可以参考以下注意事项和故障排查步骤。
确保功能门控已启用
首先,要确保 API 服务器和节点的 Kubernetes 版本都为 v1.29 或更高版本。如果节点运行的是未启用该功能的早期版本,那么在这些集群上该功能将会失效。
注意:该功能可以在 1.28 版本的节点上启用。不过 1.28 版本中内置边车容器的终止行为有所不同,不建议将边车容器的行为调整为该版本的行为。但是,如果仅关注启动顺序,上述表述可改为运行 1.28 版本且启用了功能门控的节点。
你需要确保控制平面内的 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 功能门控启用时,Pods 在其 API 中会获得一个新字段。一些工具或变异 Webhook 可能是基于早期版本的 Kubernetes API 构建的。
如果工具使用各种补丁策略原样传递未知字段来变更 Pod 对象,这不会有问题。然而,有些工具会删除未知字段;如果你使用了这类工具,就必须使用 v1.28 + 版本的 Kubernetes API 客户端代码重新编译它们。
检查方法是对经过变异准入的 Pod 使用kubectl describe pod命令。如果有工具删除了新字段(restartPolicy:Always),你将不会在命令输出中看到它。
如果你遇到此类问题,建议工具或 Webhook 的开发者使用修改对象的补丁策略,而不是进行完整的对象更新。
注意:变异 Webhook 可能会根据某些条件更新 Pods。因此,边车容器可能对某些 Pods 有效,而对其他 Pods 失效。
边车的自动注入
如果你使用的软件会自动注入边车,为了确保能够使用原生边车容器,你可以采用以下几种策略。所有策略通常都是用于决定要注入边车的 Pod 是否会被调度到支持该功能的节点上。
例如,你可以参考 Istio 社区中的这个讨论。该讨论探讨了以下几种选项:
标记支持边车的节点上的 Pods:你可以使用节点标签和节点亲和性来标记支持边车容器的节点,以及调度到这些节点上的 Pods。
在注入时检查节点兼容性:在注入边车时,你可以使用以下策略来检查节点兼容性:
查询节点版本,并假设 1.29 + 版本已启用该功能门控。
查询节点的 Prometheus 指标并检查功能启用状态。
假设节点运行的版本与 API 服务器的版本存在可支持的偏差。
可能还有其他自定义的检测节点兼容性的方法。
开发通用边车注入器:通用边车注入器的思路是同时将边车容器作为常规容器和原生边车容器进行注入,并通过运行时逻辑来决定使用哪一种。虽然通用边车注入器会导致请求资源计算两次,比较浪费资源,但在特殊情况下可以作为可行的解决方案。
一种实现方式是在原生边车容器启动时检测节点版本,如果版本不支持边车功能则立即退出。
考虑运行时功能检测设计:
定义一个空目录,以便容器之间可以相互通信。
注入一个初始化容器,我们称之为 NativeSidecar,并将restartPolicy设置为Always。
NativeSidecar 必须向空目录写入一个文件以表明这是首次运行,然后立即以退出代码 0 退出。
当原生边车受支持时,NativeSidecar 重启时会检查空目录中该文件是否已存在,并对其进行修改,以此表明内置边车容器受支持且正在运行。
注入一个常规容器,我们称之为 OldWaySidecar。
OldWaySidecar 启动时检查空目录中是否存在文件。
如果文件表明 NativeSidecar 未运行,它会认为边车功能不受支持,并将自身当作边车来工作。
如果文件表明 NativeSidecar 正在运行,在Pod’s restartPolicy=Always的情况下,它什么也不做并永远休眠;在Pod’s restartPolicy!=Always的情况下,它立即以退出代码 0 退出。