Kubernetes 1.29:服务负载均衡器 IP 模式的新(Alpha)特性

本博客介绍了 Kubernetes 1.29 中的一项新的 alpha 功能。它提供了一种可配置的方法来定义服务实现(本博客中以 kube-proxy 为例)如何处理集群内从 pod 到服务的流量。

背景

在较旧的 Kubernetes 版本中,kube-proxy 会拦截目标为与 type: LoadBalancer 服务关联的 IP 地址的流量。无论您使用 kube-proxy 的哪种模式,都会发生这种情况。拦截实现了预期的行为(流量最终到达服务背后的预期端点)。实现该功能的机制取决于 kube-proxy 的模式;在 Linux 上,iptables 模式下的 kube-proxy 会将数据包直接重定向到端点;在 ipvs 模式下,kube-proxy 会将负载均衡器的 IP 地址配置为节点上的一个接口。实施该拦截的动机有两个原因

  1. 流量路径优化:有效地重定向 pod 流量 - 当 pod 中的容器发送目标为负载均衡器 IP 地址的出站数据包时 - 通过绕过负载均衡器直接到达后端服务。

  2. 处理负载均衡器数据包:某些负载均衡器发送的数据包的目标 IP 设置为负载均衡器的 IP 地址。因此,这些数据包需要直接路由到正确的后端(可能不在该节点本地),以避免循环。

问题

然而,上述行为存在几个问题

  1. 源 IP: 一些云提供商在向节点传输数据包时使用负载均衡器的 IP 作为源 IP。在 kube-proxy 的 ipvs 模式下,存在来自负载均衡器的运行状况检查永远不会返回的问题。发生这种情况的原因是,回复数据包会转发到本地接口 kube-ipvs0(负载均衡器的 IP 绑定到此处),然后被忽略。

  2. 负载均衡器级别的功能丢失: 某些云提供商在负载均衡器级别提供功能(例如 TLS 终止、代理协议等)。绕过负载均衡器会导致数据包到达服务时丢失这些功能(导致协议错误)。

即使禁用了新的 alpha 行为(默认行为),也有一种 解决方法,即为服务设置 .status.loadBalancer.ingress.hostname,以绕过 kube-proxy 绑定。但这只是一个临时的解决方案。

解决方案

总而言之,为云提供商提供禁用当前行为的选项将非常有益。

为了解决这个问题,Kubernetes v1.29 为 Service 引入了一个新的(alpha).status.loadBalancer.ingress.ipMode 字段。此字段指定负载均衡器 IP 的行为方式,并且仅当还指定了 .status.loadBalancer.ingress.ip 字段时才可以指定。

.status.loadBalancer.ingress.ipMode 可能有两个值:"VIP""Proxy"。默认值为“VIP”,这意味着通过将目标设置为负载均衡器的 IP 和端口交付到节点的流量将由 kube-proxy 重定向到后端服务。这保留了 kube-proxy 的现有行为。“Proxy”值旨在防止 kube-proxy 在 ipvs 和 iptables 模式下将负载均衡器的 IP 地址绑定到节点。因此,流量将直接发送到负载均衡器,然后转发到目标节点。转发数据包的目标设置因云提供商的负载均衡器交付流量的方式而异

  • 如果流量被传递到节点,然后被 DNAT 到 pod,则目标将被设置为节点的 IP 和节点端口;
  • 如果流量直接传递到 pod,则目标将被设置为 pod 的 IP 和端口。

用法

以下是启用此功能所需的步骤

  • 下载 最新的 Kubernetes 项目(版本 v1.29.0 或更高版本)。
  • 在 kube-proxy、kube-apiserver 和 cloud-controller-manager 上使用命令行标志 --feature-gates=LoadBalancerIPMode=true 启用功能门。
  • 对于 type: LoadBalancer 的服务,将 ipMode 设置为适当的值。此步骤很可能由您选择的 cloud-controller-manager 在 EnsureLoadBalancer 过程中处理。

更多信息

参与其中

Slack 上联系我们:#sig-network,或通过 邮件列表

鸣谢

非常感谢 @Sh4d1 的原始 KEP 和初始实现代码。我中途接手并完成了这项工作。同样,非常感谢其他帮助设计、实施和审查此功能的贡献者(按字母顺序排列)