bigywater.tech
Kubernetes · 69

EndpointSlice:Endpoints 的拆分与更新

EndpointSlice 到底解决了 Endpoints 的什么问题?后端多了会怎样拆分?一个 Pod 变化时 kube-proxy 要重新接收多少数据?Pod 终止期间 endpoint 的状态是什么?这篇在真集群里把一个 Service 的后端扩到 205 个,逐项看出来。

100 + 100 + 5
205 个后端被拆成的三个 EndpointSlice
34891 字节
同样 205 个地址的 Endpoints 对象大小;每次变化都整体重发
ready=false, serving=true
终止中 Pod 在 EndpointSlice 里的 conditions

Service 自动生成的切片

实测 · 本机执行输出
  Service s3 有 1 个 EndpointSlice;名字 s3-ls98l;labels={'endpointslice.kubernetes.io/managed-by': 'endpointslice-controller.k8s.io', 'kubernetes.io/service-name': 's3'}
  addressType=IPv4;ports=[('', 80, 'TCP')];ownerReferences=[('Service', 's3')]
  endpoints[0]:addresses=['10.244.1.45'];conditions={'ready': True, 'serving': True, 'terminating': False};nodeName=kx-main-worker;targetRef=Pod/s3-756c4bd7f-v82f9…
  共 3 个 endpoint,与 Pod 数一致:True
  旧的 Endpoints 对象 s3 也还在,含 3 个地址(kubectl 会提示 v1 Endpoints is deprecated in v1.33+,由控制器同时维护)

3 个 Pod 的 Service s3 有 1 个 EndpointSlice,带标签 kubernetes.io/service-name=s3 和 endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io,ownerReference 指向 Service。每个 endpoint 有 addresses(Pod IP)、conditions(ready/serving/terminating)、nodeName、指向 Pod 的 targetRef。旧的 Endpoints 对象还在被同步生成,kubectl 提示 v1 Endpoints is deprecated in v1.33+。

后端多了拆成多片

实测 · 本机执行输出
  扩到 205 个副本,22 秒后所有 Pod 都进了切片:3 个 EndpointSlice,各含 [100, 100, 5] 个 endpoint
  同一个 Service 的 Endpoints 对象:205 个地址,JSON 34891 字节;其中最大的一个 EndpointSlice(100 个 endpoint)的 JSON 24749 字节

扩到 205 个副本,22 秒后 3 个切片里装下了所有 Pod,分别是 100、100、5 个 endpoint(默认每片最多 100 个)。同一个 Service 的 Endpoints 是单个对象,含 205 个地址,JSON 有 34891 字节;最大的 EndpointSlice(100 个 endpoint)是 24749 字节。后端越多,Endpoints 越大。

变化只更新一个切片

实测 · 本机执行输出
  删掉 1 个 Pod 之后(Deployment 会补一个新的):1 个 EndpointSlice 的 resourceVersion 变了(共 3 个);Endpoints 对象 resourceVersion 110321 → 110344
  watch 的客户端(kube-proxy)收到更新时:Endpoints 要整个对象(34891 字节)重发一遍,EndpointSlice 只重发变了的那个切片(约 24749 字节)
  缩回 3 个副本:切片数 1(空的切片会被回收,可能保留一个)

删掉 1 个 Pod 后 Deployment 补了一个新的:3 个切片里只有 1 个的 resourceVersion 变了(这次删除和新增落在同一个切片里;不同位置可能触发 2 个)。Endpoints 则必须整个 34891 字节的对象重发给每个 watch 的客户端(kube-proxy 每个节点一个)。缩回 3 个副本后切片数回到 1:空的切片会被回收。

终止中的 endpoint

实测 · 本机执行输出
  Pod t4-7655bccb99-74… 终止前 endpoint 条件:{'ready': True, 'serving': True, 'terminating': False}
  删除后 3 秒(sleep 作 1 号进程不理 SIGTERM,要等 40 秒的 terminationGracePeriod):{'ready': False, 'serving': True, 'terminating': True}
    Service 的另一个 Pod 的条件仍是 ready:[{'ready': True, 'serving': True, 'terminating': False}]
    37 秒后这个 endpoint 从切片里消失(Pod 真正退出)

Pod 正常时 conditions 是 ready=true, serving=true, terminating=false。kubectl delete 之后(sleep 作 1 号进程不处理 SIGTERM,要等 40 秒的 terminationGracePeriodSeconds)3 秒时变成 ready=false, serving=true, terminating=true:不再接收新流量,但仍标记为在服务;同一个 Service 的另一个 Pod 仍是 ready。约 37 秒后这个 endpoint 才从切片里消失。

分步演示

EndpointSlice
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),每个工作节点最多 110 个 Pod;后端用 busybox 的 sleep;JSON 字节数是 kubectl 取到的对象用紧凑格式序列化后的长度,仅作大小对比;“只有一个切片变化”是单次观察;每种情形各一次
    • 没有验证:endpointslice 控制器的参数(--max-endpoints-per-slice)调整;EndpointSliceMirroring(手写 Endpoints 镜像成切片);拓扑感知路由(hints / trafficDistribution);双栈下的 IPv4/IPv6 切片;endpoint 数大到 Endpoints 对象被截断(1000 上限)的情形;kube-proxy 实际消费 EndpointSlice 的路径
    京ICP备2026067502号-1京公网安备11010502063487号