虚拟 IP 和服务代理
Kubernetes 集群中的每个 节点 运行一个 kube-proxy(除非您已部署自己的替代组件来代替 kube-proxy)。
kube-proxy 组件负责为 type 不是 ExternalName 的 Services 实现一个 *虚拟 IP* 机制。kube-proxy 的每个实例都会监视 Kubernetes 控制平面,以了解 Service 和 EndpointSlice 对象 的添加和删除。对于每个 Service,kube-proxy 会调用适当的 API(取决于 kube-proxy 模式)来配置节点以捕获到 Service 的 clusterIP 和 port 的流量,并将该流量重定向到 Service 的一个端点(通常是一个 Pod,但也可能是任意用户提供的 IP 地址)。一个控制循环确保每个节点上的规则与 API 服务器指示的 Service 和 EndpointSlice 状态可靠同步。
使用 iptables 模式的 Services 的虚拟 IP 机制
一个经常出现的问题是,为什么 Kubernetes 依赖于代理来转发入站流量到后端。其他方法呢?例如,是否可以配置具有多个 A 值(或 IPv6 的 AAAA)的 DNS 记录,并依赖于循环解析名称?
使用代理进行 Services 的原因有几个
- DNS 实现不遵守记录 TTL 的历史很长,并且在应该过期后缓存查找结果。
- 有些应用程序只执行一次 DNS 查找并无限期地缓存结果。
- 即使应用程序和库正确地重新解析,DNS 记录上的低或零 TTL 也可能对 DNS 施加很高的负载,然后难以管理。
在本页的后面,您可以阅读各种 kube-proxy 实现的工作方式。总的来说,您应该注意,在使用 kube-proxy 时,内核级别的规则可能会被修改(例如,可能会创建 iptables 规则),在某些情况下,在您重新启动之前不会被清理。因此,运行 kube-proxy 只能由了解拥有计算机上的低级别、特权网络代理服务的后果的管理员来完成。虽然 kube-proxy 可执行文件支持一个 cleanup 函数,但此函数不是官方功能,因此只能按原样使用。
此参考中的一些细节引用了一个示例:用于无状态图像处理工作负载的后端 Pods,运行三个副本。这些副本是可互换的——前端不关心它们使用哪个后端。虽然构成后端集的实际 Pod 可能会发生变化,但前端客户端不需要知道这一点,也不需要跟踪后端集本身。
代理模式
kube-proxy 以不同的模式启动,这些模式由其配置决定。
在 Linux 节点上,kube-proxy 可用的模式是
iptables- 一种 kube-proxy 使用 iptables API 配置数据包转发规则的模式。
ipvs- 一种 kube-proxy 使用 ipvs 配置数据包转发规则的模式。
nftables- 一种 kube-proxy 使用 nftables 配置数据包转发规则的模式。
kube-proxy 在 Windows 上只有一种模式可用
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 地址。
相同的基本流程在通过 type: NodePort Service 或通过负载均衡器接收流量时执行,尽管在这些情况下,客户端 IP 地址会发生更改。
优化 iptables 模式性能
在 iptables 模式下,kube-proxy 为每个 Service 创建几个 iptables 规则,为每个端点 IP 地址创建几个 iptables 规则。在拥有数万个 Pod 和 Service 的集群中,这意味着数万个 iptables 规则,并且当 Service(或其 EndpointSlices)发生更改时,kube-proxy 可能需要很长时间才能更新内核中的规则。您可以通过 kube-proxy 配置文件的 iptables 部分(您通过 kube-proxy --config <path> 指定)中的选项来调整 kube-proxy 的同步行为
...
iptables:
minSyncPeriod: 1s
syncPeriod: 30s
...
minSyncPeriod
minSyncPeriod 参数设置了 iptables 规则与内核同步尝试之间的最小持续时间。如果设置为 0s,则 kube-proxy 将始终在任何 Service 或 EndpointSlice 发生更改时立即同步规则。这在非常小的集群中可以正常工作,但在短时间内发生大量更改时,会导致大量冗余工作。例如,如果您有一个由 Deployment 支持的 100 个 Pod 的 Service,然后您删除了 Deployment,那么使用 minSyncPeriod: 0s,kube-proxy 将最终逐个从 iptables 规则中删除 Service 的端点,总共进行 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 在每次同步时都会更新所有 Service 的所有规则;这导致大型集群中的性能问题(更新滞后),推荐的解决方案是设置更大的 minSyncPeriod。从 Kubernetes v1.28 开始,kube-proxy 的 iptables 模式使用更精简的方法,仅对实际发生更改的 Service 或 EndpointSlice 进行更新。
如果您之前曾覆盖 minSyncPeriod,您应该尝试删除该覆盖并让 kube-proxy 使用默认值 (1s),或者至少使用比升级前更小的值。
如果您没有运行 Kubernetes 1.35 的 kube-proxy,请检查您实际运行的版本中的行为和相关建议。
syncPeriod
syncPeriod 参数控制一些与单个 Service 和 EndpointSlice 更改不直接相关的同步操作。特别是,它控制 kube-proxy 发现外部组件是否干扰了 kube-proxy 的 iptables 规则的速度。在大型集群中,kube-proxy 也仅每 syncPeriod 执行某些清理操作,以避免不必要的工作。
通常,增加 syncPeriod 不太可能对性能产生太大影响,但在过去,有时将其设置为非常大的值(例如,1h)是有用的。现在不建议这样做,并且很可能会损害功能,而不会提高性能。
IPVS 代理模式
Kubernetes v1.35 [已弃用]此代理模式仅在 Linux 节点上可用。
在 ipvs 模式下,kube-proxy 使用内核 IPVS 和 iptables API 创建规则,以将来自 Service IP 的流量重定向到端点 IP。
IPVS 代理模式基于 netfilter 钩子函数,该函数类似于 iptables 模式,但使用哈希表作为底层数据结构,并在内核空间中工作。
说明
ipvs 代理模式旨在提供具有更好规则同步性能和更高网络流量吞吐量的 Linux kube-proxy 后端。虽然它在这些目标上取得了成功,但内核 IPVS API 最终与 Kubernetes Services API 不匹配,并且 ipvs 后端无法正确实现 Kubernetes Service 功能的所有边缘情况。
下面的 nftables 代理模式基本上是 iptables 和 ipvs 模式的替代品,具有比两者更好的性能,建议将其作为 ipvs 的替代品。如果您正在部署到太旧的 Linux 系统而无法运行 nftables 代理模式,您也应该考虑尝试 iptables 模式而不是 ipvs,因为 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=ipvsmh将像源哈希 (sh) 一样工作,但带有端口。
通过 kube-proxy 配置中的 ipvs.scheduler 字段配置这些调度算法。
说明
要以 IPVS 模式运行 kube-proxy,您必须在启动 kube-proxy 之前在节点上提供 IPVS。
当 kube-proxy 以 IPVS 代理模式启动时,它会验证是否可用 IPVS 内核模块。如果未检测到 IPVS 内核模块,则 kube-proxy 将以错误退出。
使用 IPVS 模式的 Services 的虚拟 IP 地址机制
nftables 代理模式
Kubernetes v1.33 [稳定](默认启用)此代理模式仅在 Linux 节点上可用,并且需要内核 5.13 或更高版本。
在此模式下,kube-proxy 使用内核 netfilter 子系统的 nftables API 配置数据包转发规则。对于每个端点,它会安装 nftables 规则,默认情况下,随机选择后端 Pod。
nftables API 是 iptables API 的后继者,旨在提供比 iptables 更好的性能和可扩展性。nftables 代理模式能够比 iptables 模式更快、更有效地处理服务端点的更改,并且还能够更有效地处理内核中的数据包(尽管这只有在集群中拥有数万个服务时才会变得明显)。
截至 Kubernetes 1.35,nftables 模式仍然相对较新,可能与并非所有网络插件兼容;请参阅您的网络插件的文档。
从 iptables 模式迁移到 nftables
希望从默认 iptables 模式切换到 nftables 模式的用户应注意,某些功能在 nftables 模式下工作方式略有不同
NodePort 接口:在
iptables模式下,默认情况下,NodePort 服务 可以在所有本地 IP 地址上访问。这通常不是用户想要的,因此nftables模式默认设置为--nodeport-addresses primary,这意味着使用type: NodePort的服务只能在节点的 IPv4 和/或 IPv6 主要地址上访问。可以通过为该选项指定显式值来覆盖此设置:例如,--nodeport-addresses 0.0.0.0/0以侦听所有(本地)IPv4 IP。type: NodePort服务在127.0.0.1上:在iptables模式下,如果--nodeport-addresses范围包括127.0.0.1(并且未传递--iptables-localhost-nodeports false选项),则即使在“localhost”(127.0.0.1)上也可以访问type: NodePort服务。在nftables模式(和ipvs模式)中,这不起作用。如果您不确定是否依赖此功能,可以检查 kube-proxy 的iptables_localhost_nodeports_accepted_packets_total指标;如果它不为 0,则表示某些客户端已通过 localhost/loopback 连接到type: NodePort服务。NodePort 与防火墙的交互:kube-proxy 的
iptables模式尝试与过于激进的防火墙兼容;对于每个type: NodePort服务,它将添加规则以接受入站流量在该端口上,以防该流量否则被防火墙阻止。这种方法不适用于基于 nftables 的防火墙,因此 kube-proxy 的nftables模式不执行任何操作;如果您有本地防火墙,则必须确保其已正确配置以允许 Kubernetes 流量通过(例如,允许 NodePort 范围内的所有入站流量)。Conntrack 错误解决方法:Linux 内核版本低于 6.1 存在一个错误,该错误可能导致与服务 IP 的长期 TCP 连接在出现“连接由对等方重置”错误时关闭。kube-proxy 的
iptables模式安装了一个针对此错误的解决方法,但后来发现该解决方法在某些集群中会导致其他问题。nftables模式默认情况下不安装任何解决方法,但您可以检查 kube-proxy 的iptables_ct_state_invalid_dropped_packets_total指标,以查看您的集群是否依赖于解决方法,如果是,则可以在nftables模式下使用--conntrack-tcp-be-liberal选项运行 kube-proxy 以解决该问题。
kernelspace 代理模式
此代理模式仅在 Windows 节点上可用。
kube-proxy 在 Windows 虚拟筛选平台 (VFP) 中配置数据包过滤规则,VFP 是 Windows vSwitch 的扩展。这些规则处理节点级别虚拟网络中的封装数据包,并重写数据包,以便正确地将数据包路由到正确的目的地。Windows VFP 类似于 Linux 上的 nftables 或 iptables 等工具。Windows VFP 扩展了 Hyper-V 交换机,最初是为了支持虚拟机网络而实现的。
当节点上的 Pod 向虚拟 IP 地址发送流量时,如果 kube-proxy 选择不同节点上的 Pod 作为负载均衡目标,kernelspace 代理模式会将该数据包重写为目标后端 Pod。Windows 主机网络服务 (HNS) 确保配置数据包重写规则,以便回程流量看起来来自虚拟 IP 地址,而不是特定的后端 Pod。
kernelspace 模式的直接服务器返回
Kubernetes v1.34 [稳定](默认启用)作为基本操作的替代方案,托管 Service 后端 Pod 的节点可以直接应用数据包重写,而不是将此负担放在客户端 Pod 所在的节点上。这称为直接服务器返回。
要使用此功能,必须使用 --enable-dsr 命令行参数运行 kube-proxy 并且启用 WinDSR 功能门控。
直接服务器返回还可以优化即使两个 Pod 都在同一节点上运行时的 Pod 回程流量的情况。
会话亲和性
在这些代理模型中,绑定到 Service IP:Port 的流量会被代理到合适的后端,而客户端无需了解 Kubernetes 或 Services 或 Pods 的任何信息。
如果您希望确保来自特定客户端的连接每次都传递到相同的 Pod,则可以将 .spec.sessionAffinity 设置为 ClientIP 来选择基于客户端 IP 地址的会话亲和性(默认值为 None)。
会话粘性超时
您还可以通过为 Service 适当设置 .spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大的会话粘性时间。(默认值为 10800,相当于 3 小时)。
说明
在 Windows 上,不支持为 Services 设置最大的会话粘性时间。向 Services 分配 IP 地址
与实际路由到固定目的地的 Pod IP 地址不同,Service IP 实际上并没有由单个主机响应。相反,kube-proxy 使用数据包处理逻辑(例如 Linux iptables)来定义虚拟 IP 地址,这些地址会根据需要透明地重定向。
当客户端连接到 VIP 时,他们的流量会自动传输到合适的端点。Services 的环境变量和 DNS 实际上是根据 Service 的虚拟 IP 地址(和端口)填充的。
避免冲突
Kubernetes 的主要理念之一是,您不应该遇到可能导致您的操作由于您自身无过错而失败的情况。对于 Service 资源的的设计,这意味着不要让您选择自己的 IP 地址,如果该选择可能与他人的选择冲突。那是一种隔离失败。
为了允许您为 Services 选择 IP 地址,我们必须确保没有两个 Service 会发生冲突。Kubernetes 通过从为 API Server 配置的 service-cluster-ip-range CIDR 范围内分配每个 Service 自己的 IP 地址来实现这一点。
IP 地址分配跟踪
为了确保每个 Service 收到唯一的 IP 地址,内部分配器会在创建每个 Service 之前以原子方式更新 etcd 中的全局分配映射。
在控制平面中,一个后台控制器负责创建该映射(需要支持从旧版本的 Kubernetes 迁移,这些版本使用内存锁定)。Kubernetes 还使用控制器来检查无效的分配(例如:由于管理员干预)以及清理不再由任何 Service 使用的已分配 IP 地址。
使用 Kubernetes API 进行 IP 地址分配跟踪
Kubernetes v1.33 [稳定](默认启用)控制平面用一种新的实现替换了现有的 etcd 分配器,该实现使用 IPAddress 和 ServiceCIDR 对象而不是内部全局分配映射。然后,与 Service 关联的每个集群 IP 地址都引用一个 IPAddress 对象。
启用功能门控还会用一个替代方案替换后台控制器,该控制器处理 IPAddress 对象并支持从旧分配器模型迁移。Kubernetes 1.35 不支持从 IPAddress 对象迁移到内部分配映射。
修订后的分配器的一个主要好处是,它消除了可用于 Service 集群 IP 地址的 IP 地址范围的大小限制。在启用 MultiCIDRServiceAllocator 时,对于 IPv4 没有限制,对于 IPv6,您可以使用 /64 或更小的 IP 地址网络掩码(与旧实现中的 /108 相比)。
通过 API 提供 IP 地址分配意味着作为集群管理员,您可以允许用户检查分配给其 Service 的 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/v1
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
Kubernetes 集群的发行版或管理员可能希望控制添加到集群的新 Service CIDR 是否与其他集群网络重叠,仅属于特定 IP 范围,或者只是保留每个集群只有一个 ServiceCIDR 的现有行为。实现此目的的验证准入策略示例是
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs-default"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
variables:
- name: allowed
expression: "['10.96.0.0/16','2001:db8::/64']"
validations:
- expression: "object.spec.cidrs.all(i , variables.allowed.exists(j , cidr(j).containsCIDR(i)))"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-binding"
spec:
policyName: "servicecidrs-default"
validationActions: [Deny,Audit]
---
Service 虚拟 IP 地址的 IP 地址范围
Kubernetes v1.26 [稳定]Kubernetes 根据配置的 service-cluster-ip-range 的大小,使用以下公式将 ClusterIP 范围划分为两个频段:min(max(16, cidrSize / 16), 256)。该公式意味着结果绝不会小于 16 或大于 256,它们之间有一个渐变阶跃函数。
Kubernetes 倾向于从上频段为 Services 分配动态 IP 地址,这意味着如果您想为 type: ClusterIP Service 分配特定的 IP 地址,您应该手动从下频段分配 IP 地址。这种方法降低了分配冲突的风险。
流量策略
您可以设置 .spec.internalTrafficPolicy 和 .spec.externalTrafficPolicy 字段来控制 Kubernetes 如何将流量路由到健康的(“就绪”)后端。
内部流量策略
Kubernetes v1.26 [稳定]您可以设置 .spec.internalTrafficPolicy 字段来控制如何路由来自内部源的流量。有效值为 Cluster 和 Local。将该字段设置为 Cluster 以将内部流量路由到所有就绪的端点,将该字段设置为 Local 以仅路由到就绪的节点本地端点。如果流量策略为 Local 并且没有节点本地端点,则 kube-proxy 会丢弃流量。
外部流量策略
您可以设置 .spec.externalTrafficPolicy 字段来控制如何路由来自外部源的流量。有效值为 Cluster 和 Local。将该字段设置为 Cluster 以将外部流量路由到所有就绪的端点,将该字段设置为 Local 以仅路由到就绪的节点本地端点。如果流量策略为 Local 并且没有节点本地端点,则 kube-proxy 不会转发相关 Service 的任何流量。
如果指定了 Cluster,只要节点未被删除并且 kube-proxy 正常,所有节点都有资格作为负载均衡目标。在这种模式下:负载均衡器健康检查配置为针对服务代理的就绪端口和路径。对于 kube-proxy,这相当于:${NODE_IP}:10256/healthz。kube-proxy 将返回 HTTP 代码 200 或 503。
kube-proxy 健康时,这意味着
它能够完成网络编程并不会在执行此操作时超时(超时时间定义为:2 ×
iptables.syncPeriod);并且节点未被删除(节点上未设置删除时间戳)。
kube-proxy 在被删除时会返回 503 并将节点标记为不符合条件,因为它支持终止节点的连接排空。
当删除时
- kube-proxy 将开始失败其就绪探测,并基本上将节点标记为不符合负载均衡器流量的条件。负载均衡器健康检查失败会导致支持连接排空的负载均衡器允许现有连接终止,并阻止建立新的连接。
当删除时
- Kubernetes 云控制器管理器中的服务控制器从引用的合格目标集中删除该节点。立即从负载均衡器的后端目标集中删除任何实例将终止所有连接。这也是 kube-proxy 在节点删除时首先失败健康检查的原因。
对于配置 kube-proxy 就绪探测为存活探测的 Kubernetes 供应商来说,需要注意的是:kube-proxy 在节点完全删除之前会持续重启,直到完全删除。kube-proxy 暴露了一个 /livez 路径,与 /healthz 路径不同,它不会考虑节点正在删除的状态,而只考虑其网络编程进度。因此,/livez 是任何希望为 kube-proxy 定义存活探测的人推荐的路径。
部署 kube-proxy 的用户可以通过评估指标 proxy_livez_total / proxy_healthz_total 来检查就绪/存活状态。这两个指标都发布两个序列,一个带有 200 标签,一个带有 503 标签。
对于 Local Services:kube-proxy 如果
- kube-proxy 健康/就绪,并且
- 在相关节点上有本地端点。
节点删除不会影响 kube-proxy 在负载均衡器健康检查方面的返回码。原因是:删除节点最终可能导致入站流量中断,如果所有端点同时在这些节点上运行。
Kubernetes 项目建议云提供商集成代码配置负载均衡器健康检查,以针对服务代理的 healthz 端口。如果您正在使用或实现自己的虚拟 IP 实现,供人们替代 kube-proxy 使用,您应该设置一个类似的健康检查端口,其逻辑与 kube-proxy 实现匹配。
终止端点的流量
Kubernetes v1.28 [稳定]如果 kube-proxy 中启用了 ProxyTerminatingEndpoints 功能门控,并且流量策略为 Local,则该节点的 kube-proxy 使用更复杂的算法为服务选择端点。在启用此功能后,kube-proxy 会检查节点是否具有本地端点,以及是否所有本地端点都被标记为正在终止。如果有本地端点并且全部都在终止,那么 kube-proxy 将把流量转发到这些终止端点。否则,kube-proxy 将始终优先将流量转发到未终止的端点。
这种针对终止端点的转发行为是为了允许 NodePort 和 LoadBalancer 服务在使用 externalTrafficPolicy: Local 时优雅地排空连接。
当部署经历滚动更新时,支持负载均衡器的节点可能从 N 个副本过渡到该部署的 0 个副本。在某些情况下,外部负载均衡器可以在健康检查探测之间将流量发送到具有 0 个副本的节点。将流量路由到终止端点可确保正在缩减 Pod 的节点可以优雅地接收和排空流量到这些终止的 Pod。到 Pod 完成终止时,外部负载均衡器应该已经看到节点的健康检查失败,并已完全将该节点从后端池中移除。
流量分发控制
Kubernetes Service 中的 spec.trafficDistribution 字段允许您表达如何将流量路由到服务端点的偏好。
优先同区域- 这优先将流量发送到与客户端位于同一区域的端点。EndpointSlice 控制器使用
hints更新 EndpointSlice,以传达此偏好,kube-proxy 然后将其用于路由决策。如果客户端的区域没有可用的端点,则流量将针对该客户端在整个集群中路由。 优先同节点- 这优先将流量发送到与客户端位于同一节点的端点。与
PreferSameZone类似,EndpointSlice 控制器使用hints更新 EndpointSlice,指示应将一个 slice 用于特定节点。如果客户端的节点没有可用的端点,则服务代理将回退到“同区域”行为,或者如果没有同区域端点,则回退到整个集群。 PreferClose(已弃用)- 这是
PreferSameZone的较旧别名,对语义的描述不够清晰。
如果没有为 trafficDistribution 提供任何值,则默认策略是将流量均匀地分发到集群中的所有端点。
与 service.kubernetes.io/topology-mode: Auto 的比较
具有 PreferSameZone 的 trafficDistribution 字段,以及使用 service.kubernetes.io/topology-mode: Auto 注释的较旧的“拓扑感知路由”功能,都旨在优先处理同区域流量。但是,它们的方法存在关键差异
service.kubernetes.io/topology-mode: Auto尝试根据可分配的 CPU 资源,跨区域按比例分配流量。这种启发式方法包括保障措施(例如,对于少量端点数的回退行为),牺牲了一些可预测性,以换取可能更好的负载均衡。trafficDistribution: PreferSameZone旨在更简单和更可预测:“如果区域中有端点,它们将接收该区域的所有流量,如果没有区域中的端点,则流量将分发到其他区域”。这种方法提供了更高的可预测性,但这意味着您有责任避免端点过载。
如果 service.kubernetes.io/topology-mode 注释设置为 Auto,它将优先于 trafficDistribution。该注释将来可能会被弃用,以支持 trafficDistribution 字段。
与流量策略的交互
与 trafficDistribution 字段相比,流量策略字段(externalTrafficPolicy 和 internalTrafficPolicy)旨在提供更严格的流量本地性要求。以下是 trafficDistribution 与它们交互的方式
流量策略优先级:对于给定的服务,如果流量策略(
externalTrafficPolicy或internalTrafficPolicy)设置为Local,则它优先于相应流量类型(外部或内部)的trafficDistribution。trafficDistribution影响:对于给定的服务,如果流量策略(externalTrafficPolicy或internalTrafficPolicy)设置为Cluster(默认值),或者如果这些字段未设置,则trafficDistribution指导相应流量类型(外部或内部)的路由行为。这意味着将尝试将流量路由到与客户端位于同一区域的端点。
使用流量分发控制的注意事项
使用 trafficDistribution 的服务将尝试将流量路由到适当拓扑内的(健康的)端点,即使这意味着某些端点比其他端点接收更多的流量。如果您在与客户端相同的拓扑(“同一区域”、“同一节点”等)内没有足够数量的端点,则端点可能会过载。如果传入流量未按比例分发到拓扑中,则尤其如此。为了缓解这种情况,请考虑以下策略
Pod 拓扑传播约束:使用 Pod 拓扑传播约束将您的 Pod 均匀地分布在区域或节点上。
区域特定部署:如果您正在使用“同区域”流量分发,但预计在不同区域看到不同的流量模式,您可以为每个区域创建一个单独的部署。这种方法允许单独的工作负载独立扩展。生态系统中还有工作负载管理插件可用,这些插件位于 Kubernetes 项目之外,可以提供帮助。
接下来
要了解有关服务的更多信息,请阅读 使用服务连接应用程序。
您还可以