端点切片

EndpointSlice API 是 Kubernetes 用于让你的服务扩展以处理大量后端并允许集群有效地更新其健康后端列表的机制。
功能状态: Kubernetes v1.21 [稳定]

Kubernetes 的 EndpointSlice API 提供了一种跟踪 Kubernetes 集群中网络端点的方法。EndpointSlices 提供了一种更可扩展和更灵活的替代方案,可以替代 Endpoints

EndpointSlice API

在 Kubernetes 中,EndpointSlice 包含对一组网络端点的引用。控制平面会自动为任何具有 选择器 的 Kubernetes 服务创建 EndpointSlices。这些 EndpointSlices 包含对所有匹配服务选择器的 Pod 的引用。EndpointSlices 通过协议、端口号和服务名称的唯一组合将网络端点分组在一起。EndpointSlice 对象的名称必须是有效的 DNS 子域名

例如,这是一个由 example Kubernetes 服务拥有的示例 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

默认情况下,控制平面创建和管理 EndpointSlices,使每个 EndpointSlices 不超过 100 个端点。你可以使用 --max-endpoints-per-slice kube-controller-manager 标志配置此参数,最多可达 1000 个。

当涉及到如何路由内部流量时,EndpointSlices 可以充当 kube-proxy 的事实来源。

地址类型

EndpointSlices 支持三种地址类型

  • IPv4
  • IPv6
  • FQDN(完全限定域名)

每个 EndpointSlice 对象表示特定的 IP 地址类型。如果你有一个通过 IPv4 和 IPv6 可用的服务,那么将至少有两个 EndpointSlice 对象(一个用于 IPv4,一个用于 IPv6)。

条件

EndpointSlice API 存储有关端点的条件,这些条件可能对消费者有用。这三个条件是 readyservingterminating

就绪

ready 是一个与 Pod 的 Ready 条件相映射的条件。具有 Ready 条件设置为 True 的正在运行的 Pod 应将此 EndpointSlice 条件也设置为 true。出于兼容性原因,当 Pod 正在终止时,ready 永远不会是 true。消费者应参考 serving 条件以检查正在终止的 Pod 的就绪状态。此规则的唯一例外是 spec.publishNotReadyAddresses 设置为 true 的服务。这些服务的端点将始终具有设置为 trueready 条件。

提供服务

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

serving 条件与 ready 条件几乎相同。区别在于,EndpointSlice API 的消费者如果关心 Pod 在终止时的就绪状态,则应检查 serving 条件。

正在终止

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

Terminating 是一个指示端点是否正在终止的条件。对于 Pod 来说,这指的是任何设置了删除时间戳的 Pod。

拓扑信息

EndpointSlice 中的每个端点都可以包含相关的拓扑信息。拓扑信息包括端点的地理位置以及相应节点和区域的信息。这些信息可在 EndpointSlices 上的以下每个端点字段中找到

  • nodeName - 此端点所在的节点的名称。
  • zone - 此端点所在的区域。

管理

在大多数情况下,控制平面(特别是端点切片 控制器)创建和管理 EndpointSlice 对象。EndpointSlices 还有许多其他用例,例如服务网格实现,这会导致其他实体或控制器管理额外的 EndpointSlices 集。

为了确保多个实体可以管理 EndpointSlices 而不相互干扰,Kubernetes 定义了 标签 endpointslice.kubernetes.io/managed-by,它指示管理 EndpointSlice 的实体。端点切片控制器在它管理的所有 EndpointSlices 上将 endpointslice-controller.k8s.io 设置为此标签的值。管理 EndpointSlices 的其他实体也应为此标签设置唯一的值。

所有权

在大多数用例中,EndpointSlices 由 EndpointSlice 对象跟踪端点的服务拥有。此所有权由每个 EndpointSlice 上的所有者引用以及一个 kubernetes.io/service-name 标签来指示,该标签允许简单地查找属于某个服务的全部 EndpointSlices。

EndpointSlice 镜像

在某些情况下,应用程序会创建自定义 Endpoints 资源。为了确保这些应用程序不需要同时写入 Endpoints 和 EndpointSlice 资源,集群的控制平面会将大多数 Endpoints 资源镜像到相应的 EndpointSlices。

控制平面会镜像 Endpoints 资源,除非

  • Endpoints 资源具有设置为 trueendpointslice.kubernetes.io/skip-mirror 标签。
  • Endpoints 资源具有 control-plane.alpha.kubernetes.io/leader 注释。
  • 相应的服务资源不存在。
  • 相应的服务资源具有非空选择器。

单个 Endpoints 资源可能转换为多个 EndpointSlices。如果 Endpoints 资源具有多个子集或包含具有多个 IP 族(IPv4 和 IPv6)的端点,就会发生这种情况。每个子集最多 1000 个地址将被镜像到 EndpointSlices。

EndpointSlices 的分发

每个 EndpointSlice 都有一个端口集,该端口集适用于资源中的所有端点。当服务使用命名端口时,Pod 可能会针对同一个命名端口获得不同的目标端口号,从而需要不同的 EndpointSlices。这类似于子集如何与 Endpoints 分组的逻辑。

控制平面尝试尽可能地填满 EndpointSlices,但不主动重新平衡它们。逻辑相当简单

  1. 遍历现有的 EndpointSlices,删除不再需要的端点,并更新已更改的匹配端点。
  2. 遍历在第一步中被修改的 EndpointSlices,并用所需的任何新端点填充它们。
  3. 如果仍有新的端点需要添加,请尝试将它们放入以前未更改的切片中,或创建新的切片。

重要的是,第三步优先考虑限制 EndpointSlice 更新,而不是 EndpointSlices 的完美填充分布。例如,如果要添加 10 个新端点,并且有 2 个 EndpointSlices,每个都有空间容纳 5 个额外的端点,则这种方法将创建新的 EndpointSlice,而不是填充 2 个现有的 EndpointSlices。换句话说,创建单个 EndpointSlice 比更新多个 EndpointSlices 更可取。

由于 kube-proxy 在每个节点上运行并监视 EndpointSlices,因此对 EndpointSlice 的每一次更改都相对昂贵,因为它将被传输到集群中的每个节点。这种方法旨在限制需要发送到每个节点的更改数量,即使它可能导致多个 EndpointSlices 未被填满。

在实践中,这种不太理想的分发情况应该是很少见的。EndpointSlice 控制器处理的大多数更改都足够小,可以放入现有的 EndpointSlice 中,如果没有,则可能很快就会需要新的 EndpointSlice。部署的滚动更新还提供了一种自然的方式,可以重新打包 EndpointSlices,其中所有 Pod 及其对应的端点都将被替换。

重复端点

由于 EndpointSlice 更改的性质,端点可能在同一个时间出现在多个 EndpointSlice 中。这种情况会在 Kubernetes 客户端监视/缓存中对不同 EndpointSlice 对象的更改到达时间不同时自然发生。

与 Endpoints 的比较

最初的 Endpoints API 提供了一种简单直观的方式来跟踪 Kubernetes 中的网络端点。随着 Kubernetes 集群和 服务 的增长,以处理更多流量并向更多后端 Pod 发送更多流量,最初 API 的局限性变得更加明显。最显著的是,这些局限性包括在扩展到大量网络端点时面临的挑战。

由于服务的所有网络端点都存储在一个 Endpoints 对象中,因此这些 Endpoints 对象可能会变得很大。对于保持稳定的服务(长时间内使用相同的端点集),影响不太明显;即使这样,Kubernetes 的一些用例也无法得到很好的满足。

当服务有大量后端端点,并且工作负载频繁扩展或频繁推出新更改时,对该服务单个 Endpoints 对象的每次更新都意味着 Kubernetes 集群组件之间(在控制平面内,以及节点和 API 服务器之间)存在大量流量。这种额外的流量在 CPU 使用方面也有一定的成本。

使用 EndpointSlices,添加或删除单个 Pod 会触发相同数量的更新通知观察更改的客户端,但在规模很大时,这些更新消息的大小会小得多。

EndpointSlices 还使围绕新功能(如双栈网络和拓扑感知路由)的创新成为可能。

下一步

上次修改时间:2024 年 3 月 14 日下午 2:28 PST: 向 API 参考链接添加元数据使用机制 (c889d9b251)