虚拟 IP 和服务代理

每个 Kubernetes 集群中的 节点 运行一个 kube-proxy (除非您已部署自己的替代组件来代替 kube-proxy)。

kube-proxy 组件负责实现 服务 的虚拟 IP 机制,这些服务的类型不是 ExternalName。kube-proxy 的每个实例都监视 Kubernetes 控制平面 以了解服务和 EndpointSlice 对象 的添加和删除情况。对于每个服务,kube-proxy 会调用适当的 API(取决于 kube-proxy 模式)来配置节点,以便捕获到服务 clusterIPport 的流量,并将该流量重定向到服务的其中一个端点(通常是 Pod,但也有可能是任意的用户提供的 IP 地址)。一个控制循环确保每个节点上的规则与服务和 EndpointSlice 状态保持可靠同步,如 API 服务器所示。

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

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

使用代理来处理服务有一些原因

  • DNS 实现有一个悠久的不尊重记录 TTL,并在记录应该过期后缓存名称查找结果的历史。
  • 有些应用程序只执行一次 DNS 查找,并将结果无限期地缓存。
  • 即使应用程序和库确实进行了适当的重新解析,DNS 记录上的低 TTL 或零 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。

示例

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

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

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

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

优化 iptables 模式性能

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

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

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

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

1s 的默认值应该在大多数集群中运行良好,但在非常大的集群中,可能需要将其设置为更大的值。特别是,如果 kube-proxy 的 sync_proxy_rules_duration_seconds 指标表明平均时间远远超过 1 秒,那么增加 minSyncPeriod 可能会使更新更有效率。

更新旧的 minSyncPeriod 配置

旧版本的 kube-proxy 在每次同步时都会更新所有服务的全部规则;这会导致大型集群中出现性能问题(更新延迟),建议的解决方案是设置更大的 minSyncPeriod。从 Kubernetes v1.28 开始,kube-proxy 的 iptables 模式使用更简化的方式,只对实际发生变化的服务或 EndpointSlices 进行更新。

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

如果您没有运行 Kubernetes 1.31 中的 kube-proxy,请检查您实际运行的版本的行为和相关建议。

syncPeriod

syncPeriod 参数控制一些与单个服务和 EndpointSlices 更改无关的同步操作。具体来说,它控制着 kube-proxy 发现外部组件是否干预了 kube-proxy 的 iptables 规则的速度。在大型集群中,kube-proxy 还会每 syncPeriod 执行一次某些清理操作,以避免不必要的操作。

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

IPVS 代理模式

这种代理模式只在 Linux 节点上可用。

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

IPVS 代理模式基于 netfilter 钩子函数,类似于 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 行为。

使用 IPVS 模式的 Service 的虚拟 IP 地址机制

nftables 代理模式

功能状态: Kubernetes v1.31 [beta]

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

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

nftables API 是 iptables API 的继任者,旨在提供比 iptables 更好的性能和可扩展性。nftables 代理模式能够比 iptables 模式更快、更有效地处理服务端点更改,并且能够更有效地处理内核中的数据包(尽管这只有在拥有数万个服务的集群中才会显而易见)。

从 Kubernetes 1.31 开始,nftables 模式仍然相对较新,可能与所有网络插件不兼容;请参阅网络插件的文档。

iptables 模式迁移到 nftables

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

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

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

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

  • Conntrack 错误解决方法:6.1 之前的 Linux 内核存在一个错误,可能会导致对服务 IP 的长期 TCP 连接关闭,并显示错误“连接重置由对端重置”。kube-proxy 的 iptables 模式安装了针对此错误的解决方法,但后来发现此解决方法会在某些集群中导致其他问题。nftables 模式默认不安装任何解决方法,但您可以检查 kube-proxy 的 iptables_ct_state_invalid_dropped_packets_total 指标以查看您的集群是否依赖于此解决方法,如果依赖,则可以使用选项 --conntrack-tcp-be-liberalnftables 模式下解决此问题。

kernelspace 代理模式

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

kube-proxy 在 Windows 虚拟过滤平台 (VFP) 中配置数据包过滤规则,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]

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

要使用此功能,您必须使用 --enable-dsr 命令行参数运行 kube-proxy,并且启用 WinDSR 功能特性

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

会话亲和性

在这些代理模型中,绑定到服务 IP:端口的流量会代理到适当的后端,而客户端不知道 Kubernetes、服务或 Pod 的任何信息。

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

会话粘性超时

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

分配给服务的 IP 地址

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

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

避免冲突

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

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

IP 地址分配跟踪

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

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

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

功能状态: Kubernetes v1.31 [beta]

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

启用功能特性还会用一个替代方案替换后台控制器,该替代方案处理 IPAddress 对象并支持从旧分配器模型迁移。Kubernetes 1.31 不支持从 IPAddress 对象迁移到内部分配映射。

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

通过 API 提供 IP 地址分配意味着您作为集群管理员可以允许用户检查分配给其服务的 IP 地址。Kubernetes 扩展(如 网关 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 对象动态定义服务的可用 IP 范围。在引导过程中,从 kube-apiserver 的 --service-cluster-ip-range 命令行参数的值创建名为 kubernetes 的默认 ServiceCIDR 对象

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

用户可以创建或删除新的 ServiceCIDR 对象以管理服务的可用 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

服务虚拟 IP 地址的 IP 地址范围

功能特性状态: Kubernetes v1.26 [稳定]

Kubernetes 根据配置的 service-cluster-ip-range 大小,使用以下公式 min(max(16, cidrSize / 16), 256)ClusterIP 范围划分为两个频段。该公式意指永远不小于 16,也不大于 256,并且在它们之间有一个渐变的阶梯函数

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

流量策略

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

内部流量策略

功能特性状态: Kubernetes v1.26 [稳定]

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

外部流量策略

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

如果指定了 Cluster,所有节点都是合格的负载均衡目标,只要节点未被删除且 kube-proxy 处于健康状态。在这种模式下:负载均衡器健康检查被配置为针对服务代理的就绪端口和路径。在 kube-proxy 的情况下,这相当于:${NODE_IP}:10256/healthz。kube-proxy 将返回 HTTP 代码 200 或 503。kube-proxy 的负载均衡器健康检查端点在以下情况下返回 200

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

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

在删除期间

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

删除时

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

重要的是要注意,对于 Kubernetes 供应商来说,如果任何供应商将 kube-proxy 就绪探测配置为存活性探测:那么 kube-proxy 将在节点被删除时持续重新启动,直到它被完全删除。kube-proxy 公开了 /livez 路径,与 /healthz 路径不同,它考虑节点的删除状态,只考虑其推进网络编程。因此,/livez 是为希望为 kube-proxy 定义存活性探测的任何人推荐的路径。

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

对于 Local 服务:kube-proxy 将在以下情况下返回 200

  1. kube-proxy 处于健康/就绪状态,并且
  2. 在相关节点上有一个本地端点。

节点删除不会影响 kube-proxy 对负载均衡器健康检查的返回值。这样做的原因是:删除节点可能会导致所有端点同时在这些节点上运行时出现入口故障。

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

到终止端点的流量

功能特性状态: Kubernetes v1.28 [稳定]

如果在 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]

Kubernetes 服务中的 spec.trafficDistribution 字段允许您表达对如何将流量路由到服务端点的偏好。kube-proxy 等实现将 spec.trafficDistribution 字段用作指南。与给定偏好相关的行为可能会在不同实现之间略有不同。

kube-proxy 的 PreferClose
对于 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 Topology Spread Constraints:使用 Pod Topology Spread Constraints 将您的 Pod 更均匀地分布在区域中。

    • 区域特定的部署:如果您预期看到偏斜的流量模式,请为每个区域创建一个单独的部署。这种方法允许独立扩展单独的工作负载。生态系统中还提供了工作负载管理附加组件,这些附加组件可以帮助您解决此问题,它们独立于 Kubernetes 项目本身。

  • 实现特定的行为:每个数据平面实现可能以略微不同的方式处理此字段。如果您使用的是 kube-proxy 以外的实现,请参考该实现的特定文档以了解此字段是如何处理的。

下一步

要了解更多关于服务的信息,请阅读 使用服务连接应用程序

您也可以

上次修改时间:2024 年 6 月 24 日上午 9:54 PST:KEP1880:毕业到 beta (9c209a8ac6)