EndpointSlice
Kubernetes v1.21 [稳定]
Kubernetes 的 EndpointSlice API 提供了一种在 Kubernetes 集群中跟踪网络端点的方式。
EndpointSlice API
在 Kubernetes 中,EndpointSlice 包含一组网络端点的引用。对于任何指定了选择器(selector)的 Kubernetes Service,控制平面会自动创建 EndpointSlice。这些 EndpointSlice 包含对所有与 Service 选择器匹配的 Pod 的引用。EndpointSlice 通过 IP family、协议、端口号和 Service 名称的独特组合将网络端点分组在一起。EndpointSlice 对象的名称必须是合法的DNS 子域名。
举例来说,这是一个由 example
Kubernetes Service 拥有的示例 EndpointSlice 对象。
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-abc
labels:
kubernetes.io/service-name: example
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.1.2.3"
conditions:
ready: true
hostname: pod-1
nodeName: node-1
zone: us-west2-a
默认情况下,控制平面创建和管理 EndpointSlice,使其每个最多包含 100 个端点。你可以通过 kube-controller-manager 的 --max-endpoints-per-slice
标志来配置此限制,最大可达 1000。
EndpointSlice 是 kube-proxy 关于如何路由内部流量的真相来源。
地址类型
EndpointSlice 支持两种地址类型
- IPv4
- IPv6
每个 EndpointSlice
对象代表一种特定的 IP 地址类型。如果你有一个 Service 通过 IPv4 和 IPv6 都可用,那么至少会有两个 EndpointSlice
对象(一个用于 IPv4,一个用于 IPv6)。
条件
EndpointSlice API 存储了对消费者可能有用的端点条件。这三个条件是 serving
(服务中)、terminating
(终止中)和 ready
(就绪)。
Serving (服务中)
Kubernetes v1.26 [稳定]
serving
条件表示该端点当前正在提供响应,因此应将其用作 Service 流量的目标。对于由 Pod 支持的端点,这映射到 Pod 的 Ready
条件。
Terminating (终止中)
Kubernetes v1.26 [稳定]
terminating
条件表示该端点正在终止。对于由 Pod 支持的端点,当 Pod 首次被删除时(即,当它接收到删除时间戳时,很可能在 Pod 容器退出之前)就会设置此条件。
Service 代理通常会忽略处于 terminating
状态的端点,但如果所有可用端点都处于 terminating
状态,它们可能会将流量路由到同时处于 serving
和 terminating
状态的端点。(这有助于确保在底层 Pod 滚动更新期间不会丢失 Service 流量。)
Ready (就绪)
ready
条件本质上是检查“serving
且非 terminating
”的快捷方式(尽管对于 spec.publishNotReadyAddresses
设置为 true
的 Service,它也总是 true
)。
拓扑信息
EndpointSlice 中的每个端点都可以包含相关的拓扑信息。拓扑信息包括端点的位置以及有关相应 Node 和 zone 的信息。这些信息可以在 EndpointSlice 中每个端点的以下字段中找到:
nodeName
- 此端点所在的 Node 名称。zone
- 此端点所在的 zone。
管理
通常,控制平面(特别是 endpoint slice 控制器)创建和管理 EndpointSlice 对象。EndpointSlice 还有许多其他用例,例如服务网格实现,这可能导致其他实体或控制器管理额外的 EndpointSlice 集合。
为了确保多个实体可以管理 EndpointSlice 而互不干扰,Kubernetes 定义了 标签 endpointslice.kubernetes.io/managed-by
,该标签指示管理 EndpointSlice 的实体。endpoint slice 控制器在其管理的所有 EndpointSlice 上将此标签的值设置为 endpointslice-controller.k8s.io
。管理 EndpointSlice 的其他实体也应为该标签设置唯一值。
所有权
在大多数用例中,EndpointSlice 由其跟踪端点的 Service 所拥有。这种所有权通过每个 EndpointSlice 上的 owner reference (所有者引用) 和一个 kubernetes.io/service-name
标签来表示,该标签使得简单地查找属于某个 Service 的所有 EndpointSlice 成为可能。
EndpointSlice 分布
每个 EndpointSlice 都有一组适用于资源内所有端点的端口。当 Service 使用命名端口时,Pod 对于同一命名端口可能最终使用不同的目标端口号,这就需要不同的 EndpointSlice。
控制平面会尽可能将 EndpointSlice 填充满,但不会主动重新平衡它们。其逻辑相当简单:
- 遍历现有的 EndpointSlice,移除不再需要的端点,并更新已更改的匹配端点。
- 遍历第一步中已修改的 EndpointSlice,并用所需的任何新端点填充它们。
- 如果仍有新的端点需要添加,尝试将它们放入之前未更改的 slice 中和/或创建新的 slice。
重要的是,第三步优先考虑限制 EndpointSlice 更新,而不是实现完全均匀的 EndpointSlice 分布。例如,如果有 10 个新端点要添加,而有两个 EndpointSlice 各有 5 个端点的空间,这种方法将创建一个新的 EndpointSlice,而不是填满这两个现有的 EndpointSlice。换句话说,创建单个 EndpointSlice 比更新多个 EndpointSlice 更可取。
随着 kube-proxy 在每个 Node 上运行并监视 EndpointSlice,对 EndpointSlice 的每次更改都相对昂贵,因为它将被传输到集群中的每个 Node。这种方法旨在限制需要发送到每个 Node 的更改数量,即使这可能导致多个 EndpointSlice 未满。
在实践中,这种不够理想的分布应该很少见。EndpointSlice 控制器处理的大多数更改都足够小,可以放入现有的 EndpointSlice 中,如果不是,新的 EndpointSlice 反正很快可能就会成为必需。Deployment 的滚动更新也提供了一种自然的 EndpointSlice 重新打包,所有 Pod 及其相应的端点都会被替换。
重复端点
由于 EndpointSlice 更改的性质,端点可能同时出现在多个 EndpointSlice 中。这很自然地发生,因为对不同 EndpointSlice 对象的更改可能在不同的时间到达 Kubernetes 客户端 watch / 缓存。
注意
EndpointSlice API 的客户端必须遍历与 Service 相关的所有现有 EndpointSlice,并构建唯一的网络端点的完整列表。需要指出的是,端点可能在不同的 EndpointSlice 中重复。
你可以在 kube-proxy
中的 EndpointSliceCache
代码中找到执行此端点聚合和去重操作的参考实现。
EndpointSlice 镜像
Kubernetes v1.33 [已废弃]
EndpointSlice API 是对旧 Endpoints API 的替代。为了兼容那些期望 kube-proxy 基于 Endpoints 资源路由流量的旧版控制器和用户工作负载,集群的控制平面会将大多数用户创建的 Endpoints 资源镜像到相应的 EndpointSlice。
(然而,此特性与 Endpoints API 的其余部分一样,已被废弃。手动为无选择器 Service 指定端点的用户应直接创建 EndpointSlice 资源,而不是创建 Endpoints 资源并允许它们被镜像。)
控制平面会镜像 Endpoints 资源,除非:
- Endpoints 资源带有
endpointslice.kubernetes.io/skip-mirror
标签且值为true
。 - Endpoints 资源带有
control-plane.alpha.kubernetes.io/leader
注解。 - 相应的 Service 资源不存在。
- 相应的 Service 资源带有非空的 selector (选择器)。
单个 Endpoints 资源可能会转化为多个 EndpointSlice。如果 Endpoints 资源有多个 subset 或包含具有多种 IP family(IPv4 和 IPv6)的端点,就会发生这种情况。每个 subset 最多 1000 个地址将被镜像到 EndpointSlice。
接下来
- 阅读通过 Service 连接应用教程。
- 阅读 EndpointSlice API 的API 参考
- 阅读 Endpoints API 的API 参考