虛擬 IP 和服務代理

Kubernetes 叢集中的每個節點都會執行 kube-proxy(除非您已部署自己的替代組件來取代 kube-proxy)。

kube-proxy 组件负责为 type 类型不是 ExternalName服务(Services) 实现虚拟 IP 机制。kube-proxy 的每个实例都会监视 Kubernetes 控制平面,以了解服务(Service)和 EndpointSlice 对象 的新增和移除。对于每个服务,kube-proxy 会调用适当的 API(取决于 kube-proxy 模式)来配置节点,以捕获到服务的 clusterIPport 的流量,并将该流量重定向到服务的一个端点(通常是 Pod,但也可能是用户提供的任意 IP 地址)。控制回路确保每个节点上的规则与 API 服务器指示的服务和 EndpointSlice 状态可靠地同步。

服务(Services)的虚拟 IP 机制,使用 iptables 模式

一个时常出现的问题是,为什么 Kubernetes 依赖代理来转发入站流量到后端。其他方法呢?例如,是否可以配置具有多个 A 值(或 IPv6 的 AAAA)的 DNS 记录,并依赖轮询域名解析?

使用代理来实现服务(Services)有几个原因

  • DNS 实现长期以来存在不遵守记录 TTL,并在记录应该过期后仍缓存域名查找结果的历史。
  • 有些应用程式只进行一次 DNS 查找,并将结果无限期地缓存。
  • 即使应用程式和库确实进行了适当的重新解析,DNS 记录上过低或为零的 TTL 也可能对 DNS 施加高负载,进而变得难以管理。

稍后在本页中,您可以阅读有关各种 kube-proxy 实现如何运作的内容。总而言之,您应该注意,当运行 kube-proxy 时,内核级别的规则可能会被修改(例如,可能会创建 iptables 规则),在某些情况下,这些规则在您重新启动之前不会被清除。因此,运行 kube-proxy 应该是只有了解在计算机上运行低级别、特权网络代理服务的后果的管理员才能做的事情。虽然 kube-proxy 可执行文件支持 cleanup 功能,但此功能并非正式功能,因此仅按原样提供使用。

本参考中的某些细节参考了一个范例:无状态图像处理工作负载的后端 Pod,以三个副本运行。这些副本是可互换的——前端不在乎它们使用哪个后端。虽然组成后端集的实际 Pod 可能会更改,但前端客户端不应该需要知道这一点,也不应该需要跟踪后端集本身。

代理模式

kube-proxy 以不同的模式启动,这些模式由其配置决定。

在 Linux 节点上,kube-proxy 的可用模式为

iptables
一种模式,其中 kube-proxy 使用 iptables 配置数据包转发规则。
ipvs
一种模式,其中 kube-proxy 使用 ipvs 配置数据包转发规则。
nftables
一种模式,其中 kube-proxy 使用 nftables 配置数据包转发规则。

在 Windows 上,kube-proxy 只有一种可用模式

kernelspace
一种模式,其中 kube-proxy 在 Windows 内核中配置数据包转发规则

iptables 代理模式

此代理模式仅在 Linux 节点上可用。

在此模式下,kube-proxy 使用内核 netfilter 子系统的 iptables API 配置数据包转发规则。对于每个端点,它会安装 iptables 规则,默认情况下,这些规则会随机选择一个后端 Pod。

范例

作为一个范例,考虑本页 前面 描述的图像处理应用程式。当后端服务(Service)被创建时,Kubernetes 控制平面会分配一个虚拟 IP 地址,例如 10.0.0.1。对于此范例,假设服务(Service)端口为 1234。集群中的所有 kube-proxy 实例都会观察到新服务(Service)的创建。

当节点上的 kube-proxy 看到新服务(Service)时,它会安装一系列 iptables 规则,这些规则会将流量从虚拟 IP 地址重定向到更多 iptables 规则,这些规则是按服务(Service)定义的。按服务(Service)的规则链接到每个后端端点的进一步规则,而按端点的规则将流量(使用目标 NAT)重定向到后端。

当客户端连接到服务(Service)的虚拟 IP 地址时,iptables 规则会生效。选择一个后端(基于会话亲和性或随机),并将数据包重定向到后端,而无需重写客户端 IP 地址。

当流量通过节点端口或负载均衡器进入时,也会执行相同的基本流程,尽管在这些情况下,客户端 IP 地址确实会被更改。

优化 iptables 模式性能

在 iptables 模式下,kube-proxy 为每个服务(Service)创建一些 iptables 规则,并为每个端点 IP 地址创建一些 iptables 规则。在具有数万个 Pod 和服务(Services)的集群中,这意味着数万个 iptables 规则,并且当服务(Services)(或它们的 EndpointSlices)更改时,kube-proxy 可能需要很长时间才能更新内核中的规则。您可以通过 kube-proxy 配置文件iptables 部分 中的选项调整 kube-proxy 的同步行为(您可以通过 kube-proxy --config <path> 指定该配置文件)

...
iptables:
  minSyncPeriod: 1s
  syncPeriod: 30s
...
minSyncPeriod

minSyncPeriod 参数设置尝试将 iptables 规则与内核重新同步的最小持续时间。如果设置为 0s,则每次服务(Service)或端点发生更改时,kube-proxy 将始终立即同步规则。这在非常小的集群中效果很好,但是当短时间内发生大量更改时,会导致大量冗余工作。例如,如果您有一个由 100 个 Pod 的 部署(Deployment) 支持的服务(Service),并且您删除了该部署(Deployment),那么在 minSyncPeriod: 0s 的情况下,kube-proxy 最终会从 iptables 规则中逐个删除服务(Service)的端点,总共进行 100 次更新。使用更大的 minSyncPeriod,多个 Pod 删除事件将被聚合在一起,因此 kube-proxy 可能会改为进行 5 次更新,每次删除 20 个端点,这在 CPU 方面将更有效率,并导致更快地同步整套更改。

minSyncPeriod 的值越大,可以聚合的工作就越多,但缺点是每个单独的更改可能最终会等待长达完整的 minSyncPeriod 才能被处理,这意味着 iptables 规则会花费更多时间与当前的 API 服务器状态不同步。

默认值 1s 在大多数集群中应该都能很好地工作,但在非常大的集群中,可能需要将其设置为更大的值。特别是,如果 kube-proxysync_proxy_rules_duration_seconds 指标指示的平均时间远大于 1 秒,则增加 minSyncPeriod 可能会使更新更有效率。

更新旧版 minSyncPeriod 配置

旧版本的 kube-proxy 在每次同步时更新所有服务(Services)的所有规则;这导致大型集群中出现性能问题(更新延迟),建议的解决方案是设置更大的 minSyncPeriod。自 Kubernetes v1.28 以来,kube-proxy 的 iptables 模式使用了一种更精简的方法,仅在服务(Services)或 EndpointSlices 实际更改时才进行更新。

如果您以前覆盖了 minSyncPeriod,则应尝试删除该覆盖,并让 kube-proxy 使用默认值 (1s),或者至少使用比升级前使用的值更小的值。

如果您不是从 Kubernetes 1.32 运行 kube-proxy,请查看您实际运行的版本的行为和相关建议。

syncPeriod

syncPeriod 参数控制一些与单个服务(Services)和 EndpointSlices 的更改没有直接关系的同步操作。特别是,它控制 kube-proxy 多快注意到外部组件是否干扰了 kube-proxy 的 iptables 规则。在大型集群中,kube-proxy 也仅每 syncPeriod 执行一次某些清理操作,以避免不必要的工作。

在大多数情况下,增加 syncPeriod 预计不会对性能产生太大影响,但在过去,有时将其设置为非常大的值(例如,1 小时)很有用。现在不再建议这样做,并且很可能会损害功能,而不是提高性能。

IPVS 代理模式

此代理模式仅在 Linux 节点上可用。

ipvs 模式下,kube-proxy 使用内核 IPVS 和 iptables API 来创建规则,以将流量从服务(Service)IP 重定向到端点 IP。

IPVS 代理模式基于 netfilter hook 函数,该函数类似于 iptables 模式,但使用哈希表作为底层数据结构,并在内核空间中工作。这意味着 IPVS 模式下的 kube-proxy 比 iptables 模式下的 kube-proxy 以更低的延迟重定向流量,并且在同步代理规则时具有更好的性能。与 iptables 代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 为后端 Pod 提供更多负载均衡流量的选项;这些选项是

  • rr(轮询):流量在后端服务器之间平均分配。

  • wrr(加权轮询):流量根据服务器的权重路由到后端服务器。权重较高的服务器接收新连接,并获得比权重较低的服务器更多的请求。

  • lc(最少连接):更多流量被分配给活动连接较少的服务器。

  • wlc(加权最少连接):更多流量被路由到相对于其权重连接较少的服务器,即连接数除以权重。

  • lblc(基于位置的最少连接):如果服务器未过载且可用,则将同一 IP 地址的流量发送到同一后端服务器;否则,流量将发送到连接较少的服务器,并保留以供将来分配。

  • lblcr(具有复制功能的基于位置的最少连接):将同一 IP 地址的流量发送到连接最少的服务器。如果所有后端服务器都过载,它会选择一个连接较少的服务器并将其添加到目标集中。如果目标集在指定时间内未更改,则会从该集中删除负载最高的服务器,以避免高度复制。

  • sh(源哈希):通过查找基于源 IP 地址的静态分配哈希表,将流量发送到后端服务器。

  • dh(目标哈希):通过查找基于其目标地址的静态分配哈希表,将流量发送到后端服务器。

  • sed(最短预期延迟):流量转发到预期延迟最短的后端服务器。如果发送到服务器,则预期延迟为 (C + 1) / U,其中 C 是服务器上的连接数,U 是服务器的固定服务速率(权重)。

  • nq(永不排队):如果有空闲服务器,则将流量发送到空闲服务器,而不是等待快速服务器;如果所有服务器都很忙,则该算法会回退到 sed 行为。

  • mh(Maglev 哈希):根据 Google 的 Maglev 哈希算法 分配传入作业。此调度器有两个标志:mh-fallback,如果选定的服务器不可用,则启用回退到其他服务器,以及 mh-port,它将源端口号添加到哈希计算中。当使用 mh 时,kube-proxy 始终设置 mh-port 标志,并且不启用 mh-fallback 标志。在 proxy-mode=ipvs 中,mh 将作为源哈希 (sh) 工作,但带有端口。

这些调度算法通过 kube-proxy 配置中的 ipvs.scheduler 字段进行配置。

服务(Services)的虚拟 IP 地址机制,使用 IPVS 模式

nftables 代理模式

功能状态: Kubernetes v1.31 [beta](默认启用:true)

此代理模式仅在 Linux 节点上可用,并且需要内核 5.13 或更高版本。

在此模式下,kube-proxy 使用内核 netfilter 子系统的 nftables API 配置数据包转发规则。对于每个端点,它会安装 nftables 规则,默认情况下,这些规则会随机选择一个后端 Pod。

nftables API 是 iptables API 的后继者,旨在提供比 iptables 更好的性能和可扩展性。nftables 代理模式能够比 iptables 模式更快、更高效地处理服务(Service)端点的更改,并且还能够更有效地处理内核中的数据包(尽管这仅在具有数万个服务(Services)的集群中才变得明显)。

截至 Kubernetes 1.32,nftables 模式仍然相对较新,并且可能与并非所有网络插件兼容;请查阅您的网络插件的文档。

iptables 模式迁移到 nftables

想要从默认的 iptables 模式切换到 nftables 模式的用户应该注意,某些功能在 nftables 模式下的工作方式略有不同

  • NodePort 接口:在 iptables 模式下,默认情况下,NodePort 服务(Services) 在所有本地 IP 地址上都可访问。这通常不是用户想要的,因此 nftables 模式默认为 --nodeport-addresses primary,这意味着 NodePort 服务(Services)仅在节点的首选 IPv4 和/或 IPv6 地址上可访问。您可以通过为此选项指定显式值来覆盖此设置:例如,--nodeport-addresses 0.0.0.0/0 以侦听所有(本地)IPv4 IP。

  • 127.0.0.1 上的 NodePort 服务(Services):在 iptables 模式下,如果 --nodeport-addresses 范围包含 127.0.0.1(并且未传递 --iptables-localhost-nodeports false 选项),则即使在 “localhost” (127.0.0.1) 上,NodePort 服务(Services)也可访问。在 nftables 模式(和 ipvs 模式)下,这将不起作用。如果您不确定是否依赖此功能,可以检查 kube-proxyiptables_localhost_nodeports_accepted_packets_total 指标;如果它不是 0,则表示某些客户端已通过 127.0.0.1 连接到 NodePort 服务(Service)。

  • NodePort 与防火墙的交互kube-proxyiptables 模式试图与过于激进的防火墙兼容;对于每个 NodePort 服务(Service),它将添加规则以接受该端口上的入站流量,以防该流量原本会被防火墙阻止。此方法不适用于基于 nftables 的防火墙,因此 kube-proxynftables 模式在此处不执行任何操作;如果您有本地防火墙,则必须确保已正确配置该防火墙以允许 Kubernetes 流量通过(例如,通过允许整个 NodePort 范围内的入站流量)。

  • Conntrack 错误解决方法:6.1 之前的 Linux 内核存在一个错误,该错误可能导致与服务(Service)IP 的长期 TCP 连接因错误 “Connection reset by peer” 而关闭。kube-proxyiptables 模式安装了此错误的解决方法,但后来发现此解决方法在某些集群中会导致其他问题。nftables 模式默认不安装任何解决方法,但您可以检查 kube-proxyiptables_ct_state_invalid_dropped_packets_total 指标,以查看您的集群是否依赖于该解决方法,如果是,则可以使用选项 --conntrack-tcp-be-liberal 运行 kube-proxy,以解决 nftables 模式下的问题。

kernelspace 代理模式

此代理模式仅在 Windows 节点上可用。

kube-proxy 在 Windows *虚拟筛选平台* (VFP)(Windows vSwitch 的扩展)中配置数据包过滤规则。这些规则处理节点级虚拟网络中的封装数据包,并重写数据包,使目标 IP 地址(和第 2 层信息)正确,以便将数据包路由到正确的目的地。Windows VFP 类似于 Linux nftablesiptables 等工具。Windows VFP 扩展了 *Hyper-V 交换器*,最初是为了支持虚拟机网络而实现的。

当节点上的 Pod 将流量发送到虚拟 IP 地址,并且 kube-proxy 选择不同节点上的 Pod 作为负载均衡目标时,kernelspace 代理模式会重写该数据包,使其目标为目标后端 Pod。Windows *主机网络服务* (HNS) 确保配置数据包重写规则,以便返回流量看起来来自虚拟 IP 地址,而不是特定的后端 Pod。

kernelspace 模式的直接服务器返回

功能状态: Kubernetes v1.14 [alpha]

作为基本操作的替代方案,托管服务(Service)后端 Pod 的节点可以直接应用数据包重写,而不是将此负担放在客户端 Pod 正在运行的节点上。这称为直接服务器返回

要使用此功能,您必须使用 --enable-dsr 命令行参数运行 kube-proxy 启用 WinDSR 功能闸门

即使当两个 Pod 都运行在同一节点上时,直接服务器返回也可以优化 Pod 返回流量的情况。

会话亲和性

在这些代理模型中,绑定到服务(Service)的 IP:端口的流量被代理到适当的后端,而客户端对 Kubernetes 或服务(Services)或 Pod 一无所知。

如果您想确保来自特定客户端的连接每次都传递到同一个 Pod,则可以通过将服务(Service)的 .spec.sessionAffinity 设置为 ClientIP 来选择基于客户端 IP 地址的会话亲和性(默认为 None)。

会话粘性超时

您还可以通过为服务(Service)适当地设置 .spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大会话粘性时间。(默认值为 10800,即 3 小时)。

为服务(Services)分配 IP 地址

与实际路由到固定目的地的 Pod IP 地址不同,服务(Service)IP 实际上不是由单个主机应答的。相反,kube-proxy 使用数据包处理逻辑(例如 Linux iptables)来定义虚拟 IP 地址,这些地址会根据需要透明地重定向。

当客户端连接到 VIP 时,它们的流量会自动传输到适当的端点。服务(Services)的环境变量和 DNS 实际上是根据服务(Service)的虚拟 IP 地址(和端口)填充的。

避免冲突

Kubernetes 的主要理念之一是,您不应暴露于可能因非您自身过错而导致操作失败的情况。对于服务(Service)资源的设计,这意味着不让您选择自己的 IP 地址,如果该选择可能与他人的选择冲突。那是一种隔离失败。

为了允许您为服务(Services)选择 IP 地址,我们必须确保没有两个服务(Services)会发生冲突。Kubernetes 通过从为 API 服务器 配置的 service-cluster-ip-range CIDR 范围内为每个服务(Service)分配其自己的 IP 地址来实现这一点。

IP 地址分配跟踪

为了确保每个服务(Service)都收到唯一的 IP 地址,内部分配器在创建每个服务(Service)之前,以原子方式更新 etcd 中的全局分配映射。映射对象必须存在于注册表中,服务(Services)才能获得 IP 地址分配,否则创建将失败,并显示一条消息,指示无法分配 IP 地址。

在控制平面中,后台控制器负责创建该映射(需要支持从使用内存锁定的旧版本 Kubernetes 进行迁移)。Kubernetes 还使用控制器来检查无效分配(例如:由于管理员干预)以及清理不再被任何服务(Services)使用的已分配 IP 地址。

使用 Kubernetes API 进行 IP 地址分配跟踪

功能状态: Kubernetes v1.31 [beta](默认启用:false)

如果您启用 MultiCIDRServiceAllocator 功能闸门networking.k8s.io/v1alpha1 API 群组,则控制平面会将现有的 etcd 分配器替换为修订后的实现,该实现使用 IPAddress 和 ServiceCIDR 对象,而不是内部全局分配映射。然后,与服务(Service)关联的每个集群 IP 地址都引用一个 IPAddress 对象。

启用功能闸门还会将后台控制器替换为处理 IPAddress 对象并支持从旧分配器模型迁移的替代方案。Kubernetes 1.32 不支持从 IPAddress 对象迁移到内部分配映射。

修订后的分配器的主要优势之一是,它消除了可用于服务(Services)的集群 IP 地址的 IP 地址范围的大小限制。启用 MultiCIDRServiceAllocator 后,IPv4 没有限制,对于 IPv6,您可以使用 /64 或更小的 IP 地址网络掩码(而不是旧版实现的 /108)。

通过 API 提供 IP 地址分配意味着作为集群管理员,您可以允许用户检查分配给其服务(Services)的 IP 地址。Kubernetes 扩展,例如 Gateway API,可以使用 IPAddress API 来扩展 Kubernetes 固有的网络功能。

这是一个用户查询 IP 地址的简短范例

kubectl get services
NAME         TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   2001:db8:1:2::1   <none>        443/TCP   3d1h
kubectl get ipaddresses
NAME              PARENTREF
2001:db8:1:2::1   services/default/kubernetes
2001:db8:1:2::a   services/kube-system/kube-dns

Kubernetes 还允许用户使用 ServiceCIDR 对象动态定义服务(Services)的可用 IP 范围。在引导期间,会从 kube-apiserver--service-cluster-ip-range 命令行参数的值创建名为 kubernetes 的默认 ServiceCIDR 对象

kubectl get servicecidrs
NAME         CIDRS         AGE
kubernetes   10.96.0.0/28  17m

用户可以创建或删除新的 ServiceCIDR 对象来管理服务(Services)的可用 IP 范围

cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
  name: newservicecidr
spec:
  cidrs:
  - 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created
kubectl get servicecidrs
NAME             CIDRS         AGE
kubernetes       10.96.0.0/28  17m
newservicecidr   10.96.0.0/24  7m

服务(Service)虚拟 IP 地址的 IP 地址范围

功能状态: Kubernetes v1.26 [stable]

Kubernetes 使用以下公式 min(max(16, cidrSize / 16), 256),根据配置的 service-cluster-ip-range 的大小将 ClusterIP 范围划分为两个频段。该公式可以解释为永不小于 16 或大于 256,并在两者之间具有渐变步进函数

Kubernetes 倾向于通过从上频段中选择来为服务(Services)分配动态 IP 地址,这意味着如果您想为 type: ClusterIP 服务(Service)分配特定的 IP 地址,则应手动从频段分配 IP 地址。这种方法降低了分配冲突的风险。

流量策略

您可以设置 .spec.internalTrafficPolicy.spec.externalTrafficPolicy 字段来控制 Kubernetes 如何将流量路由到健康的(“就绪”)后端。

内部流量策略

功能状态: Kubernetes v1.26 [stable]

您可以设置 .spec.internalTrafficPolicy 字段来控制如何路由来自内部来源的流量。有效值为 ClusterLocal。将字段设置为 Cluster 以将内部流量路由到所有就绪端点,设置为 Local 以仅路由到就绪的节点本地端点。如果流量策略为 Local 且没有节点本地端点,则流量将被 kube-proxy 丢弃。

外部流量策略

您可以设置 .spec.externalTrafficPolicy 字段来控制如何路由来自外部来源的流量。有效值为 ClusterLocal。将字段设置为 Cluster 以将外部流量路由到所有就绪端点,设置为 Local 以仅路由到就绪的节点本地端点。如果流量策略为 Local 且没有节点本地端点,则 kube-proxy 不会转发任何相关服务(Service)的流量。

如果指定了 Cluster,则所有节点都有资格作为负载均衡目标只要节点未被删除且 kube-proxy 运行正常。在此模式下:负载均衡器健康检查被配置为以服务(Service)代理的就绪端口和路径为目标。在 kube-proxy 的情况下,这评估为:${NODE_IP}:10256/healthzkube-proxy 将返回 HTTP 代码 200 或 503。如果 kube-proxy 负载均衡器健康检查端点返回 200,则表示

  1. kube-proxy 运行正常,这意味着
    • 它能够推进网络编程,并且在执行此操作时不会超时(超时时间定义为:2 × iptables.syncPeriod);并且
  2. 节点未被删除(未为节点设置删除时间戳)。

kube-proxy 在被删除时返回 503 并将节点标记为不合格的原因是,kube-proxy 支持终止节点的连接耗尽。当节点正在被/已被删除时,从 Kubernetes 管理的负载均衡器的角度来看,会发生一些重要的事情。

正在删除时

  • kube-proxy 将开始使其就绪探针失败,并实际上将节点标记为不符合负载均衡器流量的条件。负载均衡器健康检查失败会导致支持连接耗尽的负载均衡器允许现有连接终止,并阻止建立新连接。

删除后

  • Kubernetes 云控制器管理器中的服务(Service)控制器从引用的合格目标集中删除节点。从负载均衡器的后端目标集中删除任何实例都会立即终止所有连接。这也是 kube-proxy 在节点删除时首先使健康检查失败的原因。

对于 Kubernetes 供应商来说,重要的是要注意,如果任何供应商将 kube-proxy 就绪探针配置为存活探针:则当节点正在删除直到完全删除时,kube-proxy 将开始持续重启。kube-proxy 公开了一个 /livez 路径,与 /healthz 路径相反,/livez 路径考虑节点的删除状态,而仅考虑其网络编程的进度。因此,/livez 是任何想要为 kube-proxy 定义存活探针的人员的推荐路径。

部署 kube-proxy 的用户可以通过评估指标来检查就绪/存活状态:proxy_livez_total / proxy_healthz_total。这两个指标都发布了两个序列,一个带有 200 标签,另一个带有 503 标签。

对于 Local 服务(Services):如果 kube-proxy 返回 200,则表示

  1. kube-proxy 运行正常/就绪,并且
  2. 在有问题的节点上具有本地端点。

节点删除对 kube-proxy 关于负载均衡器健康检查的返回值没有影响。原因是:如果所有端点同时在所述节点上运行,则删除节点最终可能会导致入口中断。

Kubernetes 项目建议云提供商集成代码配置以服务(Service)代理的 healthz 端口为目标的负载均衡器健康检查。如果您正在使用或实现您自己的虚拟 IP 实现,人们可以使用它来代替 kube-proxy,则应设置类似的健康检查端口,其逻辑与 kube-proxy 实现匹配。

到终止端点的流量

功能状态: Kubernetes v1.28 [stable]

如果在 kube-proxy 中啟用 ProxyTerminatingEndpoints 功能閘道,且流量策略為 Local,則該節點的 kube-proxy 會使用更複雜的演算法來選取服務的端點。啟用此功能後,kube-proxy 會檢查節點是否具有本機端點,以及是否所有本機端點都標記為終止中。如果存在本機端點,且所有本機端點都正在終止,則 kube-proxy 會將流量轉發到這些終止中的端點。否則,kube-proxy 將始終優先將流量轉發到非終止中的端點。

終止中端點的這種轉發行為,是為了讓 NodePortLoadBalancer 服務在使用 externalTrafficPolicy: Local 時能夠優雅地排空連線。

當部署進行滾動更新時,支援負載平衡器的節點可能會從 N 個副本轉換為該部署的 0 個副本。在某些情況下,外部負載平衡器可能會在健康檢查探測之間將流量傳送到具有 0 個副本的節點。將流量路由到終止中的端點可確保正在縮減 Pod 規模的節點可以優雅地接收流量並將流量排空到這些終止中的 Pod。在 Pod 完成終止時,外部負載平衡器應該已經看到節點的健康檢查失敗,並已將該節點完全從後端池中移除。

流量分配

功能状态: Kubernetes v1.31 [beta](默认启用:true)

Kubernetes 服務中的 spec.trafficDistribution 欄位允許您表達流量應如何路由到服務端點的偏好。諸如 kube-proxy 之類的實作會將 spec.trafficDistribution 欄位作為指南。與給定偏好相關聯的行為在不同實作之間可能會略有不同。

PreferClose 與 kube-proxy
對於 kube-proxy,這表示優先將流量傳送到與用戶端位於相同區域內的端點。EndpointSlice 控制器會使用 hints 更新 EndpointSlice,以傳達此偏好,然後 kube-proxy 會將其用於路由決策。如果用戶端的區域沒有任何可用的端點,則該用戶端的流量將會在叢集範圍內路由。

在沒有 trafficDistribution 任何值的情況下,kube-proxy 的預設路由策略是將流量分配到叢集中的任何端點。

service.kubernetes.io/topology-mode: Auto 的比較

具有 PreferClosetrafficDistribution 欄位和 service.kubernetes.io/topology-mode: Auto 註解都旨在優先處理同區域流量。但是,它們的方法存在關鍵差異

  • service.kubernetes.io/topology-mode: Auto:嘗試根據可分配的 CPU 資源,按比例在各個區域之間分配流量。此啟發式方法包含安全措施(例如,針對少量端點的回退行為),並可能導致在某些負載平衡情況下停用此功能。這種方法犧牲了一些可預測性,以換取潛在的負載平衡。

  • trafficDistribution: PreferClose:此方法旨在稍微簡單且更可預測:「如果區域中有端點,它們將接收該區域的所有流量;如果區域中沒有端點,則流量將分配到其他區域」。雖然這種方法可能提供更高的可預測性,但這也意味著您需要控制管理潛在的過載

如果 service.kubernetes.io/topology-mode 註解設定為 Auto,則它將優先於 trafficDistribution。(該註解未來可能會被棄用,轉而支持 trafficDistribution 欄位)。

與流量策略的互動

trafficDistribution 欄位相比,流量策略欄位(externalTrafficPolicyinternalTrafficPolicy)旨在提供更嚴格的流量本機性要求。以下是 trafficDistribution 如何與它們互動

  • 流量策略的優先順序:對於給定的服務,如果流量策略(externalTrafficPolicyinternalTrafficPolicy)設定為 Local,則對於對應的流量類型(分別為外部或內部流量),它將優先於 trafficDistribution: PreferClose

  • trafficDistribution 影響:對於給定的服務,如果流量策略(externalTrafficPolicyinternalTrafficPolicy)設定為 Cluster(預設值),或者如果未設定這些欄位,則 trafficDistribution: PreferClose 會引導對應流量類型(分別為外部或內部流量)的路由行為。這表示將嘗試將流量路由到與用戶端位於相同區域的端點。

使用流量分配控制的考量

  • 端點過載的可能性增加: PreferClose 啟發式方法將嘗試將流量路由到最近的健康端點,而不是將流量均勻地分散到所有端點。如果您的區域內沒有足夠數量的端點,它們可能會變得過載。如果傳入的流量未按比例分配到各個區域,則尤其可能發生這種情況。為了緩解這種情況,請考慮以下策略

    • Pod 拓撲分散約束:使用 Pod 拓撲分散約束,將您的 Pod 更均勻地分散到各個區域。

    • 區域特定的部署:如果您預期會看到傾斜的流量模式,請為每個區域建立單獨的部署。這種方法允許單獨的工作負載獨立擴展。生態系統中還有可用的工作負載管理附加元件,它們不屬於 Kubernetes 專案本身,可以在此處提供幫助。

  • 實作特定的行為: 每個資料平面實作可能會稍微不同地處理此欄位。如果您使用的實作不是 kube-proxy,請參閱該實作的特定文件,以了解如何處理此欄位。

下一步

若要瞭解有關服務的更多資訊,請閱讀使用服務連線應用程式

您也可以

上次修改時間:2024 年 10 月 07 日下午 2:00 PST:補充 IPVS 的描述 (9dbbfe258c)