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