Service 是如何通过 Label Selector 找到后端 Pod 的?
在 Kubernetes 中,Service 并不是直接“物理连接”到 Pod 的,而是通过一种松耦合的机制——Label Selector(标签选择器) 来动态关联后端 Pod。
这个过程的核心在于控制平面(Control Plane)如何将定义的“规则”转化为实际的“网络端点”。以下是详细的工作原理和流程:
1. 核心概念:Label 与 Selector 的匹配
这是最基础的逻辑层。
- Pod (被动方): 在定义 Pod 时,会在
metadata.labels中打上键值对标签(Key-Value Tags)。 - Service (主动方): 在定义 Service 时,会在
spec.selector中声明它想要寻找的标签。
匹配规则:
Service 的 Selector 定义的是一个子集。只有当一个 Pod 包含了 Service Selector 中声明的所有标签(Key 和 Value 都必须完全一致),这个 Pod 才会被选中。
示例 YAML
# 1. Pod 定义
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app # <--- 标签 1
env: production # <--- 标签 2
tier: frontend
# ...
---
# 2. Service 定义
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app # <--- 匹配条件 1
env: production # <--- 匹配条件 2
ports:
- port: 80
在这个例子中,Service 会找到所有同时拥有 app: my-app 和 env: production 的 Pod。
2. 关键中间层:Endpoints (或 EndpointSlice)
很多初学者认为 Service 直接指向 Pod,其实不然。中间有一个至关重要的资源对象叫做 Endpoints。
- Service 定义了访问策略和选择规则。
- Pod 是实际运行的负载,拥有具体的 Cluster IP。
- Endpoints 是它们之间的桥梁。它是一个列表,存储了所有通过 Label Selector 筛选出来的 Pod 的 IP 地址和端口。
流程: 当你创建一个带有 Selector 的 Service 时,Kubernetes 会自动创建一个同名的 Endpoints 对象。
3. 幕后推手:Endpoint Controller
是谁在执行“寻找”和“更新”的动作?是 Kubernetes 控制管理器(kube-controller-manager)中的 Endpoint Controller。
它是如何工作的:
- Watch(监听): Endpoint Controller 持续监听 API Server 中 Service 和 Pod 的变化。
- Select(筛选):
- 当一个新的 Service 被创建,或者现有的 Service Selector 被修改时,Controller 会遍历集群中的 Pod,寻找匹配 Label 的 Pod。
- 当一个新的 Pod 被创建(且状态为 Running/Ready),或者 Pod 的 Label 被修改时,Controller 也会检查它是否符合某个 Service 的 Selector。
- Update(更新):
- Controller 获取匹配 Pod 的 IP 地址(PodIP)。
- 它将这些 IP 地址列表写入到与 Service 同名的 Endpoints 对象中。
- 如果 Pod 挂了(Readiness Probe 失败或被删除),Controller 会将其 IP 从 Endpoints 列表中移除。
4. 流量转发:Kube-proxy
到目前为止,我们只是更新了数据库(Etcd)里的信息。真正的流量是如何转发的?这由运行在每个节点上的 kube-proxy 负责。
- 监听: kube-proxy 监听 API Server 中 Service 和 Endpoints 的变化。
- 配置规则: 当 Endpoints 列表发生变化(例如 Pod 扩容,IP 变了),kube-proxy 会读取这些新的 IP。
- 写入内核: kube-proxy 会在节点上配置负载均衡规则(通常是 iptables 或 IPVS)。
- 规则逻辑:凡是访问
Service_IP:Port的流量,通过随机(或轮询)的方式,DNAT(目标地址转换)到Endpoints列表中的某一个Pod_IP:Port。
- 规则逻辑:凡是访问
5. 进阶:EndpointSlices (现代 K8s 的优化)
在 Kubernetes v1.21+ 版本后,为了解决大规模集群中 Endpoints 对象过大导致的性能问题,引入了 EndpointSlices。
- 原理不变: Label Selector 的匹配逻辑不变。
- 存储改变: 以前所有的 Pod IP 都塞在一个 Endpoints 对象里;现在切分成多个小的 EndpointSlice 对象。
- 控制器: 由 EndpointSlice Controller 负责管理。
总结流程图
- 用户 创建带有 Labels 的 Pod。
- 用户 创建带有 Selector 的 Service。
- Endpoint Controller (控制平面) 发现匹配关系 -> 收集 Pod IP -> 创建/更新 Endpoints 对象。
- Kube-proxy (节点) 发现 Endpoints 变化 -> 更新本机的 iptables/IPVS 规则。
- 流量 访问 Service IP -> 被 iptables 规则拦截 -> 转发到具体的 Pod IP。
所以,Service 通过 Label Selector 找到 Pod,本质上是一个控制平面的自动化服务发现过程,最终体现为 Endpoints 对象中的 IP 列表。