K8S Service 原理
在 Kubernetes 中,Service 的创建过程涉及多个组件的协作,包括 API Server、kube-proxy、Endpoint Controller 等。以下是 Service 创建的详细流程,从 YAML 提交到最终生效的完整过程:
1. 用户提交 Service 定义(YAML/JSON)
用户通过 kubectl apply -f service.yaml 提交一个 Service 定义,例如:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 选择标签为 app: nginx 的 Pod
ports:
- protocol: TCP
port: 80 # Service 暴露的端口
targetPort: 80 # Pod 监听的端口
type: ClusterIP # 默认类型2. API Server 接收并存储 Service 定义
- API Server 是 Kubernetes 的“大脑”,负责接收所有资源创建/更新请求。
- Service 的定义会被持久化存储到 etcd(Kubernetes 的分布式键值数据库)。
3. Endpoint Controller 监听 Service 和 Pod 变化
- Endpoint Controller(运行在 Controller Manager 中)会监听两类资源:
- Service 的创建/更新/删除事件。
- Pod 的变动(如新建、删除、标签变更)。
- 关键动作:
- 根据 Service 的
selector(如app: nginx)筛选匹配的 Pod。 - 生成 Endpoints 对象(或更新现有的),记录当前匹配 Pod 的 IP 和端口列表。
- 根据 Service 的
kubectl get endpoints nginx-service输出示例:
NAME ENDPOINTS AGE
nginx-service 10.244.1.2:80,10.244.2.3:80 5s- 如果没有任何 Pod 匹配 `selector`,Endpoints 列表为空(但 Service 仍存在)。4. kube-proxy 监听 Service 和 Endpoints 变化
- kube-proxy 运行在每个节点上,负责实现 Service 的流量转发逻辑。
- 它通过监听 API Server 获取以下信息:
- Service 的虚拟 IP(ClusterIP)和端口。
- Endpoints 中 Pod 的 IP列表。
- 根据模式(iptables/IPVS)更新节点网络规则:
(1)iptables 模式(默认)
- kube-proxy 会在节点的 iptables 中插入规则:
- 当访问
ClusterIP:Port时,DNAT(目标地址转换)到某个 Pod IP。 - 使用
random或probability算法实现负载均衡。
- 当访问
- 查看规则示例:
iptables-save | grep nginx-service(2)IPVS 模式(高性能)
- kube-proxy 直接调用 Linux 内核的 IPVS 模块:
- 创建虚拟服务器(VIP = ClusterIP)。
- 添加多个真实服务器(Real Server = Pod IP)。
- 查看规则示例:
ipvsadm -Ln5. DNS Controller 更新 Service 的 DNS 记录
- CoreDNS(或 kube-dns)会监听 Service 的创建:
- 为 Service 分配一个 DNS 名称,格式为
<service-name>.<namespace>.svc.cluster.local。 - 例如,
nginx-service.default.svc.cluster.local解析到 ClusterIP。
- 为 Service 分配一个 DNS 名称,格式为
- 集群内的 Pod 可以通过 DNS 名称访问 Service,无需硬编码 IP。
6. 完整流程示例
假设创建一个 ClusterIP 类型的 Service:
- 用户提交 YAML:
kubectl apply -f nginx-service.yaml- API Server 存储到 etcd。
- Endpoint Controller 发现 Service 和匹配的 Pod,生成 Endpoints。
- kube-proxy 在各节点更新 iptables/IPVS 规则。
- CoreDNS 添加 Service 的 DNS 记录。
- 其他 Pod 可通过以下方式访问 Service:
- DNS 名称:
nginx-service.default.svc.cluster.local - ClusterIP:
10.96.123.456:80 - 流量会被自动转发到后端的 Pod(如
10.244.1.2:80)。
- DNS 名称:
7. 关键组件交互图
+---------+ +------------+ +---------------+ +-----------+
| kubectl | ----> | API Server | ----> | Endpoint Ctrl | ----> | Endpoints |
+---------+ +------------+ +---------------+ +-----------+
|
v
+------------+ +---------------+ +----------------+ +-----+
| kube-proxy | <---- | Service Watch | <---- | Endpoints Watch | <-- | Pods |
+------------+ +---------------+ +----------------+ +-----+
|
v
+------------------+
| iptables/IPVS规则 |
+------------------+8. 验证 Service 创建是否成功
- 检查 Service 和 Endpoints:
kubectl get svc nginx-service
kubectl get endpoints nginx-service- 检查 DNS 解析(在 Pod 内执行):
nslookup nginx-service.default.svc.cluster.local- 检查节点上的 iptables/IPVS 规则:
iptables-save | grep nginx-service # iptables 模式
ipvsadm -Ln | grep 10.96.123.456 # IPVS 模式9. 高级场景
(1)Headless Service(无头服务)
- 设置
clusterIP: None,不分配 ClusterIP。 - DNS 直接返回 Pod IP 列表(适用于 StatefulSet)。
(2)Session Affinity(会话保持)
- 通过
sessionAffinity: ClientIP让同一客户端的请求固定到同一个 Pod。
(3)ExternalName Service
- 将 Service 映射到外部 DNS(如数据库服务):
kind: Service
spec:
type: ExternalName
externalName: mysql.example.com总结
| 步骤 | 关键组件 | 动作 |
|---|---|---|
| 1. 提交 YAML | kubectl/API Server | 接收并存储 Service 定义到 etcd |
| 2. 匹配 Pod | Endpoint Controller | 根据 selector 生成 Endpoints 对象 |
| 3. 配置转发规则 | kube-proxy | 更新 iptables/IPVS 规则 |
| 4. 注册 DNS | CoreDNS | 添加 Service 的 DNS 记录 |
| 5. 流量代理 | kube-proxy | 将请求转发到后端 Pod |
Service 的创建过程体现了 Kubernetes 的 声明式 API 和 控制器模式,通过多个组件的协作,最终实现“一组 Pod 的访问抽象”。