这篇文章已经一年多了,较旧的文章可能包含过时的内容。请检查从发表以来,页面中的信息是否变得不正确。

Kubernetes v1.26:Kubernetes 中流量工程的进步

作者:Andrew Sy Kim (Google)

译者:Wilson Wu (DaoCloud)

Kubernetes v1.26 在网络流量工程方面取得了重大进展, 两项功能(服务内部流量策略支持和 EndpointSlice 终止状况)升级为正式发布版本, 第三项功能(代理终止端点)升级为 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 到 Pod 的网络数据路径。然后,控制器将集群中的所有可用节点添加到负载均衡器的后端池中, 使用 Service 的指定 NodePort 作为后端目标端口。

图 1:Service 负载均衡器概览

图 1:Service 负载均衡器概览

通常,为 Service 设置 externalTrafficPolicy: Local 是有益的, 对于没有运行为该 Service 提供服务的健康 Pod 的节点而言,可以避免在这类节点之间的额外跳转。 使用 externalTrafficPolicy: Local 时,会分配一个额外的 NodePort 用于健康检查, 这样不包含健康 Pod 的节点就会被排除在负载均衡器的后端池之外。

图 2:当 externalTrafficPolicy 为 Local 时,从负载均衡器到健康节点的流量情况

图 2:当 externalTrafficPolicy 为 Local 时,从负载均衡器到健康节点的流量情况

流量可能丢失的一种情况是,当节点失去了某个 Service 的所有 Pod,但外部负载均衡器尚未通过 NodePort 进行健康检查探测时。这种情况的发生概率很大程度上取决于负载均衡器上配置的健康检查时间间隔。 间隔越大,发生这种情况的可能性就越大,因为即使在 kube-proxy 删除了该服务的转发规则之后, 负载均衡器仍将继续向节点发送流量。当 Pod 在滚动更新期间开始终止时也会发生这种情况。 由于 Kubernetes 不会将正在终止的 Pod 视为“Ready”,因此当滚动更新期间任何给定节点上仅存在正在终止的 Pod 时,流量可能会丢失。

图 3:当 externalTrafficPolicy 为 Local 时,从负载均衡器到正在终止的端点的流量

图 3:当 externalTrafficPolicy 为 Local 时,从负载均衡器到正在终止的端点的流量

从 Kubernetes v1.26 开始,kube-proxy 将默认启用 ProxyTerminatingEndpoints 功能, 该功能在流量将被丢弃时自动添加故障转移并将流量路由到正在终止的端点。更具体地说, 当存在滚动更新并且节点仅包含正在终止的 Pod 时,kube-proxy 会根据其就绪情况将流量路由到正在终止的 Pod 中。 此外,如果只有正在终止的 Pod 可用时,kube-proxy 将主动使 NodePort 的健康检查失败。 通过这种做法,kube-proxy 能够提醒外部负载均衡器新连接不应发送到该节点,并妥善处理现有连接的请求。

图 4:当 externalTrafficPolicy 为 Local 时,从负载均衡器到启用 ProxyTerminateEndpoints 的正在终止端点的流量

图 4:当 externalTrafficPolicy 为 Local 时,从负载均衡器到启用 ProxyTerminateEndpoints 的正在终止端点的流量

EndpointSlice 状况

为了支持 kube-proxy 中的这一新功能,EndpointSlice API 为端点引入了新状况:servingterminating

图 5:EndpointSlice 状况概述

图 5:EndpointSlice 状况概述

serving 状况在语义上与 ready 相同,只是在 Pod 正在终止时它可以为 truefalse, 而 ready 则由于兼容性原因对于正在终止的 Pod 始终为 false。 对于正在终止的 Pod(deletionTimestamp 不为空),terminating 状况为 true,否则为 false。

添加这两个状况使该 API 的使用者能够了解之前无法体现的 Pod 状态。 例如,我们现在可以同时跟踪“ready”和“not ready”的正在终止的 Pod。

图 6:正在终止 Pod 的 EndpointSlice 状况

图 6:正在终止 Pod 的 EndpointSlice 状况

EndpointSlice API 的使用者(例如 Kube-proxy 和 Ingress Controller)现在可以使用这些状况来协调连接耗尽事件, 方法是继续转发现有连接的流量,但将新连接重新路由到其他非正在终止的端点。

优化内部节点本地流量

与 Service 可以设置 externalTrafficPolicy: Local 以避免外部来源流量的额外跃点类似, Kubernetes 现在支持 internalTrafficPolicy: Local,以便对源自集群内部的流量启用相同的优化, 特别是对于使用 Service 集群 IP 的流量目标地址。该功能已在 Kubernetes v1.24 中升级为 Beta,并在 v1.26 中升级为正式发布版本。

Service 默认将 internalTrafficPolicy 字段设置为Cluster,使其流量随机分配到所有端点。

图 7:internalTrafficPolicy 为 Cluster 时的 Service 路由

图 7:internalTrafficPolicy 为 Cluster 时的 Service 路由

internalTrafficPolicy 设置为 Local 时,仅当在相同节点存在本地可用端点时,kube-proxy 才会转发服务的内部流量。

图 8:internalTrafficPolicy 为 Local 时的服务路由

图 8:internalTrafficPolicy 为 Local 时的服务路由

欢迎参与

如果你对未来关于 Kubernetes 流量工程的讨论感兴趣,可以通过以下方式参与 SIG Network: