Service 服务发现
Pod 的 IP 每次重建都会变化,客户端不可能追着 Pod 跑。Service 为「一组提供相同功能的 Pod」提供稳定入口:一个固定虚拟 IP 与域名,并把请求负载均衡转发到后端多个 Pod,这是集群内服务发现的基石。
为什么需要 Service:Pod IP 漂移
滚动更新、节点故障、手动删除都会让 Pod 销毁重建,IP 随之改变:
kubectl get pods -o wide # 记下当前 Pod 的 IP
kubectl delete pod web-xxxxx # 删掉一个 Pod
kubectl get pods -o wide # 新 Pod 的 IP 已经变了
客户端直连 Pod IP 一变就连不上;Service 的 IP 长期稳定,后端增减自动同步。
核心机制:selector 与 Endpoint
Service 用 spec.selector 匹配带相应 Label 的 Pod,匹配结果收集为 Endpoint(新版本由 EndpointSlice 承载),kube-proxy 据此维护转发规则:
kubectl get endpoints myapp
# 输出:NAME ENDPOINTS AGE
# myapp 10.244.1.5:8080,10.244.1.6:8080 2m
Service 的四种类型
| type | 语义 | 典型用途 |
|---|---|---|
| ClusterIP(默认) | 集群内部可达的虚拟 IP | 内部服务互相调用 |
| NodePort | 每台节点开放固定端口 | 集群外直接访问、测试 |
| LoadBalancer | 借助云负载均衡器暴露 | 公有云对外提供服务 |
| ExternalName | 返回一条 DNS CNAME,不转发流量 | 把集群外域名包装成内部服务 |
ClusterIP 的转发由各节点上的 kube-proxy 完成,常见 iptables 规则或性能更好的 ipvs 模式。
完整示例:Deployment + Service
先用命令创建带标签 app=myapp 的两个 Pod,再写 Service 指向它们:
kubectl create deployment myapp --image=nginx --replicas=2
kubectl get pods -l app=myapp -o wide # 确认 Pod 就绪
Service 通过 selector 找到这些 Pod 并做负载均衡:
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: ClusterIP
selector:
app: myapp # 靠标签找到上面的 Pod
ports:
- port: 80 # Service 对外端口
targetPort: 80 # 转发到 Pod 的端口
kubectl apply -f svc.yaml
kubectl get svc myapp
# 输出:NAME TYPE CLUSTER-IP PORT(S) AGE
# myapp ClusterIP 10.96.10.10 80/TCP 10s
kubectl run tmp --image=curlimages/curl -it --rm -- sh
curl http://myapp # 集群内用服务名即可访问
无选择器与 headless Service
无选择器 Service 不写 selector,手动建 Endpoint 指向外部 IP,让集群内通过服务名访问外部系统。headless Service 把 clusterIP 设为 None,不分配虚拟 IP,DNS 直接返回各 Pod 地址,常与 StatefulSet 配合:
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
clusterIP: None # headless
selector:
app: redis
ports:
- port: 6379
配合 StatefulSet 时每个 Pod 得到 podname.svcname 形式的稳定域名,有状态应用靠它互相定位。
小结:Service 用 selector 把漂移的 Pod IP 收敛成稳定入口,ClusterIP 供集群内部、NodePort/LoadBalancer 暴露外部、headless 服务于有状态应用,是访问 Pod 的第一道门。