K8s-EndpointSlice控制器流程
EndpointSlice 控制器流程
本文档描述 Kubernetes EndpointSlice 控制器如何让 Service 感知后端 Pod 变化的完整流程。
概述
EndpointSlice 控制器负责:
- 监听 Service 和 Pod 变化
- 生成和管理 EndpointSlice 资源
- 记录 Service 后端 Pod 的 IP 地址和端口
flowchart TD
subgraph APIServer["API Server"]
A["Service 资源"]
B["Pod 资源"]
C["EndpointSlice 资源"]
D["Node 资源"]
end
subgraph EndpointSliceController["EndpointSlice Controller"]
E["Watch Service"]
F["Watch Pod"]
G["Watch Node"]
H["Reconciler"]
I["serviceQueue"]
end
subgraph Consumers["消费者"]
J["kube-proxy"]
K["CoreDNS"]
L["Ingress Controller"]
end
E -->|触发| I
F -->|触发| I
G -->|触发| I
I --> H
H -->|Create/Update/Delete| C
C -->|Watch| J
C -->|Watch| K
C -->|Watch| L
style H fill:#c8e6c9
style C fill:#fff3e0
EndpointSlice vs Endpoints
| 特性 | Endpoints (旧) | EndpointSlice (新) |
|---|---|---|
| 单对象端点限制 | ~1000 | 100 (可配置) |
| 可扩展性 | 有限 | 高 |
| 拓扑感知 | 无 | 支持 Zone/Topology |
| 双栈 IP | 不支持 | 支持 IPv4/IPv6 |
| 性能 | 大规模集群有瓶颈 | 优化 |
流程详解
1. EndpointSlice Controller 架构
代码路径: pkg/controller/endpointslice/endpointslice_controller.go
1 | // Controller 管理 selector-based service endpoint slices |
2. 事件处理流程
sequenceDiagram
participant API as API Server
participant ESC as EndpointSlice Controller
participant Queue as serviceQueue
participant Reconciler as Reconciler
participant ES as EndpointSlice
API->>ESC: Pod Add/Update/Delete 事件
ESC->>ESC: addPod / updatePod / deletePod
ESC->>Queue: Enqueue Service Key
API->>ESC: Service Add/Update/Delete 事件
ESC->>ESC: onServiceUpdate / onServiceDelete
ESC->>Queue: Enqueue Service Key
Queue->>ESC: processNextServiceWorkItem
ESC->>ESC: syncService(key)
ESC->>Reconciler: Reconcile(Service, Pods, existingSlices)
Reconciler->>ES: Create/Update/Delete EndpointSlices
ES->>API: 写入 API Server
3. syncService 核心逻辑
代码路径: pkg/controller/endpointslice/endpointslice_controller.go:345
1 | func (c *Controller) syncService(logger klog.Logger, key string) error { |
4. Pod 选择与过滤
代码路径: staging/src/k8s.io/endpointslice/util/controller_utils.go
1 | // ShouldPodBeInEndpoints 判断 Pod 是否应包含在 Endpoints 中 |
5. EndpointSlice 数据结构
API 定义: api/discovery/v1/types.go
1 | type EndpointSlice struct { |
6. Reconciler 协调逻辑
代码路径: staging/src/k8s.io/endpointslice/reconciler.go
1 | func (r *Reconciler) Reconcile(logger klog.Logger, service *v1.Service, pods []*v1.Pod, existingSlices []*discovery.EndpointSlice) error { |
7. 拓扑感知 (TopologyAwareHints)
flowchart TD
subgraph Nodes["节点分布"]
N1["Node-Zone-A"]
N2["Node-Zone-A"]
N3["Node-Zone-B"]
N4["Node-Zone-B"]
end
subgraph EndpointSlices["EndpointSlice"]
E1["Endpoint (Zone-A)"]
E2["Endpoint (Zone-A)"]
E3["Endpoint (Zone-B)"]
E4["Endpoint (Zone-B)"]
end
subgraph Consumers["消费者"]
C1["Client in Zone-A"]
C2["Client in Zone-B"]
end
N1 --> E1
N2 --> E2
N3 --> E3
N4 --> E4
C1 -->|优先访问| E1
C1 -->|优先访问| E2
C2 -->|优先访问| E3
C2 -->|优先访问| E4
EndpointSlice 的 Hints 字段支持拓扑感知路由:
1 | endpoints: |
8. kube-proxy 如何使用 EndpointSlice
代码路径: pkg/proxy/endpointslicecache/endpointslice_cache.go
1 | type EndpointSliceCache struct { |
关键代码锚点
| 功能 | 文件路径 |
|---|---|
| EndpointSlice Controller | pkg/controller/endpointslice/endpointslice_controller.go:187 |
| syncService 入口 | pkg/controller/endpointslice/endpointslice_controller.go:345 |
| Reconciler | staging/src/k8s.io/endpointslice/reconciler.go |
| Pod 过滤逻辑 | staging/src/k8s.io/endpointslice/util/controller_utils.go:94 |
| kube-proxy EndpointSliceCache | pkg/proxy/endpointslicecache/endpointslice_cache.go |
EndpointSlice 示例
1 | apiVersion: discovery.k8s.io/v1 |
触发条件总结
| 事件 | 触发条件 |
|---|---|
| Pod 创建 | Pod labels 匹配 Service selector |
| Pod 更新 | Pod IP、Ready 状态、Labels 变化 |
| Pod 删除 | Pod 被删除 |
| Service 创建 | Service 有 selector |
| Service 更新 | Service selector 或 ports 变化 |
| Service 删除 | 清理关联的 EndpointSlice |
高频面试题
Q1: EndpointSlice 和传统的 Endpoints 有什么区别?
参考答案:
| 特性 | Endpoints (v1) | EndpointSlice (discovery/v1) |
|---|---|---|
| 可扩展性 | 单对象 ~1000 端点限制 | 可分片,每片最多 1000 端点 |
| 地址类型 | 混合 IPv4/IPv6 | 按 AddressType 分离 |
| 拓扑感知 | 无 | 支持 Zone/NodeName |
| 状态条件 | 只有 Ready | Ready/Serving/Terminating |
| 管理者标识 | 无 | LabelManagedBy 标签 |
| 性能 | 大规模集群瓶颈 | 优化,增量更新 |
核心优势:
- 解决大规模集群(10万+ Pod)的性能问题
- 支持拓扑感知路由(TopologyAwareHints)
- 更好的双栈 IPv4/IPv6 支持
Q2: EndpointSlice 控制器是如何工作的?
参考答案:
监听资源变化:
- Service Informer:监听 Service 创建/更新/删除
- Pod Informer:监听 Pod 变化
- Node Informer:监听节点变化(拓扑感知)
触发同步:
- Pod 变化 →
GetPodServiceMemberships找到匹配的 Service - Service 变化 → 直接触发该 Service 的同步
- 将 Service Key 加入
serviceQueue
- Pod 变化 →
同步逻辑 (syncService):
- 获取 Service 关联的 Pod 列表
- 获取现有的 EndpointSlice 列表
- 调用
Reconciler.Reconcile()计算 diff - 执行 Create/Update/Delete 操作
Pod 过滤规则:
- 终止状态(Terminating)的 Pod 不包含
- 没有 IP 的 Pod 不包含
- 未 Ready 的 Pod 根据条件判断
Q3: 什么是拓扑感知路由 (TopologyAwareHints)?
参考答案:
拓扑感知路由让客户端优先访问同一 Zone 的后端 Pod,减少跨 Zone 流量成本。
工作原理:
- EndpointSlice Controller 计算每个 Zone 的端点分布
- 为每个端点添加
hints.forZones字段 - kube-proxy 根据客户端所在 Zone 过滤端点
启用方式:
1 | apiVersion: v1 |
EndpointSlice 示例:
1 | endpoints: |
Q4: Pod 的 Ready、Serving、Terminating 条件分别是什么含义?
参考答案:
1 | type EndpointConditions struct { |
| 状态 | Ready | Serving | Terminating | 说明 |
|---|---|---|---|---|
| 正常运行 | true | true | false | 接收所有流量 |
| 未就绪 | false | false | false | 不接收流量 |
| 优雅终止中 | false | true | true | 可接收优雅终止流量 |
应用场景:
publishNotReadyAddresses: true时,即使 Ready=false 也会包含- Serving 状态用于支持优雅终止期间的流量
Q5: kube-proxy 如何使用 EndpointSlice?
参考答案:
Watch EndpointSlice:
- kube-proxy 通过 Informer 监听 EndpointSlice 变化
- 变化事件触发
OnEndpointSliceAdd/Update/Delete
EndpointSliceCache:
- 维护
trackerByServiceMap按 Service 分组 - 每个 Service 有
applied(已应用)和pending(待处理)状态 checkoutChanges()返回所有待处理的变更
- 维护
更新规则:
- 计算变更前后 的端点差异
- 更新 iptables/IPVS 规则
- 标记 pending 为 applied
代码路径: pkg/proxy/endpointslicecache/endpointslice_cache.go
Q6: 如何排查 Service 无法访问后端 Pod 的问题?
参考答案:
1 | # 1. 检查 Service 和 EndpointSlice |
延伸阅读
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Joohwan!
评论

