EndpointSlices

EndpointSlice API 是 Kubernetes 用来让您的服务扩展以处理大量后端,并允许集群高效更新其健康后端列表的机制。
特性状态: Kubernetes v1.21 [稳定]

Kubernetes 的 EndpointSlice API 提供了一种在 Kubernetes 集群中跟踪网络端点的方法。与 Endpoints 相比,EndpointSlices 提供了更具可扩展性和可扩展性的替代方案。

EndpointSlice API

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

例如,这里有一个示例 EndpointSlice 对象,它由 example Kubernetes 服务拥有。

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,每个端点不超过 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 的服务。这些服务的端点始终会将 ready 条件设置为 true

服务中

特性状态: 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 的实体。端点切片控制器将 endpointslice-controller.k8s.io 设置为此标签在其管理的所有 EndpointSlices 上的值。管理 EndpointSlices 的其他实体也应该为此标签设置唯一值。

所有权

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

EndpointSlice 镜像

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

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

  • Endpoints 资源设置了 endpointslice.kubernetes.io/skip-mirror 标签为 true
  • Endpoints 资源具有 control-plane.alpha.kubernetes.io/leader 注解。
  • 相应的 Service 资源不存在。
  • 相应的 Service 资源具有非空的 selector。

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

EndpointSlices 的分发

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

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

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

重要的是,第三步优先考虑限制 EndpointSlice 的更新,而不是完美地完全分配 EndpointSlice。例如,如果有 10 个新的端点要添加,并且有 2 个 EndpointSlice 各有 5 个端点的空间,则此方法将创建一个新的 EndpointSlice,而不是填充 2 个现有的 EndpointSlice。换句话说,创建一个 EndpointSlice 比多次更新 EndpointSlice 更可取。

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

实际上,这种不太理想的分配情况应该很少见。EndpointSlice 控制器处理的大多数更改都足够小,可以放入现有的 EndpointSlice 中,如果不能,则无论如何都可能很快需要一个新的 EndpointSlice。Deployments 的滚动更新也提供了 EndpointSlice 的自然重新打包,所有 Pod 及其相应的端点都将被替换。

重复的端点

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

与 Endpoints 的比较

原始的 Endpoints API 提供了一种简单直接的方法来跟踪 Kubernetes 中的网络端点。随着 Kubernetes 集群和服务的增长,以处理更多流量并将更多流量发送到更多后端 Pod,原始 API 的局限性变得更加明显。最值得注意的是,这些局限性包括扩展到大量网络端点的挑战。

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

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

使用 EndpointSlice,添加或删除单个 Pod 会触发相同数量的更新到正在监视更改的客户端,但在大规模情况下,这些更新消息的大小要小得多。

EndpointSlice 还促进了围绕双栈网络和拓扑感知路由等新功能的创新。

下一步

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