本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
Kubernetes v1.26:Kubernetes 流量工程的进展
Kubernetes v1.26 在网络流量工程方面取得了重大进展,其中两个特性(Service 内部流量策略支持和 EndpointSlice 终止条件)升级为正式发布(GA),第三个特性(代理终止端点)升级为 Beta 版。这些增强功能的结合旨在解决人们当前面临的流量工程短板,并为未来解锁新的能力。
滚动更新期间来自负载均衡器的流量丢失
在 Kubernetes v1.26 之前,当 externalTrafficPolicy
字段设置为 Local
时,集群在滚动更新期间可能会遇到来自 Service 负载均衡器的流量丢失问题。这里涉及很多活动部件,因此快速了解一下 Kubernetes 如何管理负载均衡器可能会有所帮助!
在 Kubernetes 中,你可以创建一个 type: LoadBalancer
的 Service,通过负载均衡器将应用程序对外暴露。负载均衡器的实现因集群和平台而异,但 Service 提供了一个通用的抽象,代表了在所有 Kubernetes 安装中都一致的负载均衡器。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: my-app
ports:
- protocol: TCP
port: 80
targetPort: 9376
type: LoadBalancer
在底层,Kubernetes 为该 Service 分配一个 NodePort,然后 kube-proxy 使用该 NodePort 提供从 NodePort 到 Pod 的网络数据路径。控制器随后会将集群中所有可用的节点添加到负载均衡器的后端池中,使用为该 Service 指定的 NodePort 作为后端目标端口。

图 1:Service 负载均衡器概览
通常,为 Service 设置 externalTrafficPolicy: Local
是有益的,以避免在没有运行健康 Pod 来支持该 Service 的节点之间产生额外的网络跳数。当使用 externalTrafficPolicy: Local
时,会额外分配一个 NodePort 用于健康检查,这样不包含健康 Pod 的节点就会从负载均衡器的后端池中排除。

图 2:当 externalTrafficPolicy 为 Local 时,负载均衡器流量流向健康节点
一种可能导致流量丢失的场景是,当一个节点失去了某个 Service 的所有 Pod,但外部负载均衡器尚未探测到健康检查 NodePort 的状态。这种情况发生的可能性很大程度上取决于负载均衡器上配置的健康检查间隔。间隔越大,这种情况就越有可能发生,因为即使在 kube-proxy 移除了该 Service 的转发规则之后,负载均衡器仍会继续向该节点发送流量。这在滚动更新期间 Pod 开始终止时也会发生。由于 Kubernetes 不认为正在终止的 Pod 是“就绪”的,因此在滚动更新期间,当任何给定节点上只有正在终止的 Pod 时,可能会发生流量丢失。

图 3:当 externalTrafficPolicy 为 Local 时,负载均衡器流量流向正在终止的端点
从 Kubernetes v1.26 开始,kube-proxy 默认启用了 ProxyTerminatingEndpoints
特性,该特性在流量否则会被丢弃的场景下,为正在终止的端点添加了自动故障转移和路由功能。更具体地说,当进行滚动更新且某个节点只包含正在终止的 Pod 时,kube-proxy 将根据它们的就绪状态将流量路由到这些正在终止的 Pod。此外,如果只有正在终止的 Pod 可用,kube-proxy 将主动使健康检查 NodePort 失败。通过这样做,kube-proxy 会通知外部负载均衡器不应将新连接发送到该节点,但会优雅地处理现有连接的请求。

图 4:当 externalTrafficPolicy 为 Local 且启用 ProxyTerminatingEndpoints 时,负载均衡器流量流向正在终止的端点
EndpointSlice 条件
为了支持 kube-proxy 中的这一新功能,EndpointSlice API 引入了针对端点的新条件:serving
和 terminating
。

图 5:EndpointSlice 条件概览
serving
条件在语义上与 ready
相同,但它在 Pod 终止期间可以是 true
或 false
,而 ready
出于兼容性原因,对于正在终止的 Pod 总是 false
。terminating
条件对于正在终止的 Pod(deletionTimestamp 非空)为 true,否则为 false。
这两个条件的增加使该 API 的使用者能够了解以前无法获知的 Pod 状态。例如,我们现在可以跟踪那些同时也在终止的“就绪”和“非就绪”的 Pod。

图 6:带有正在终止的 Pod 的 EndpointSlice 条件
EndpointSlice API 的使用者,如 Kube-proxy 和 Ingress 控制器,现在可以利用这些条件来协调连接排空事件,通过继续为现有连接转发流量,但将新连接重新路由到其他非终止的端点。
优化内部节点本地流量
类似于 Service 可以设置 externalTrafficPolicy: Local
来避免外部来源流量的额外跳数,Kubernetes 现在支持 internalTrafficPolicy: Local
,以为集群内部产生的流量(特别是以 Service Cluster IP 为目标地址的流量)实现相同的优化。该特性在 Kubernetes v1.24 中升级为 Beta 版,并在 v1.26 中升级为 GA。
Service 的 internalTrafficPolicy
字段默认为 Cluster
,此时流量会随机分配到所有端点。

图 7:当 internalTrafficPolicy 为 Cluster 时的 Service 路由
当 internalTrafficPolicy
设置为 Local
时,kube-proxy 仅在有位于同一节点上的可用端点时,才会转发 Service 的内部流量。

图 8:当 internalTrafficPolicy 为 Local 时的 Service 路由
注意
当使用internalTrafficPoliy: Local
时,如果没有可用的本地端点,流量将被 kube-proxy 丢弃。参与其中
如果你对未来 Kubernetes 流量工程的讨论感兴趣,可以通过以下方式参与 SIG Network