这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已不准确。
Kubernetes v1.26:Kubernetes 流量工程的进展
Kubernetes v1.26 在网络流量工程方面取得了重大进展,其中两项特性(Service 内部流量策略支持和 EndpointSlice 终止条件)升级到 GA,第三项特性(Proxy 终止端点)升级到 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 的网络数据路径。接着,一个控制器会将集群中所有可用的 Node 添加到负载均衡器的后端池,并将 Service 指定的 NodePort 作为后端目标端口。

图 1:Service 负载均衡器概述
通常,为 Service 设置 externalTrafficPolicy: Local
是有益的,这样可以避免流量在没有运行该 Service 背后健康 Pod 的 Node 之间进行额外的跳转。当使用 externalTrafficPolicy: Local
时,会额外分配一个用于健康检查的 NodePort,以便将不包含健康 Pod 的 Node 从负载均衡器的后端池中排除。

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

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

图 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 只会在同一 Node 上存在可用的本地端点时转发 Service 的内部流量。

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