本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

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

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

背景

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

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

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

问题

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

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

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

即使禁用了新的 alpha 行为(默认情况),也有一个变通方法,即为 Service 设置 .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 的 Service,将 ipMode 设置为适当的值。此步骤可能由你选择的 cloud-controller-manager 在 EnsureLoadBalancer 过程中处理。

更多信息

参与进来

通过 Slack 上的 #sig-network 频道或邮件列表联系我们。

致谢

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