一个 Pod 崩了重启之后 IP 就变了,那访问它的请求该怎么找到它?Service 就是解决这个问题的。
一、为什么需要 Service
Kubernetes 里的 Pod 是非常"不稳定"的------随时可能被重建、扩缩容、调度到另一个节点,每次重建 IP 都会变化。业务代码不可能直接写死 Pod IP,否则一旦 Pod 重启,上游就找不到它了。
Service 是 K8s 提供的稳定访问入口,它通过 Label Selector 动态绑定一组 Pod,对外暴露一个固定的 ClusterIP 或端口,不管后端 Pod 怎么飘,Service 的入口地址永远不变。
Service 的三大核心能力:
- 稳定虚拟 IP(ClusterIP)+ DNS 名称,屏蔽 Pod IP 变化
- 自动负载均衡,将请求分发给健康 Pod
- 支持多种暴露方式,适配集群内、集群外、云厂商 LB 等场景
二、Service 的五种类型
K8s 内置五种 Service 类型,适配不同的访问场景。
1. ClusterIP(默认类型)
定义: 为 Service 分配一个只在集群内部可路由的虚拟 IP(VIP),仅集群内的 Pod 和 Node 可访问,外部无法直接访问。
工作机制:
- kube-proxy 在每个节点维护 iptables/IPVS 规则
- 当请求命中 ClusterIP 时,被转发到 EndpointSlice 中的健康 Pod
适用场景: 微服务间内部调用(如 Web → DB、API → Cache)
yaml
apiVersion: v1
kind: Service
metadata:
name: my-svc
spec:
type: ClusterIP # 默认可省略
selector:
app: jczz_app
ports:
- port: 80 # Service 暴露的端口
targetPort: 8080 # Pod 容器实际监听端口
记忆口诀: ClusterIP = 集群内专用,外网看不见。
2. NodePort
定义: 在 ClusterIP 基础上,额外在集群每个节点 上开放一个固定端口(范围 30000-32767),外部可通过 节点IP:NodePort 访问服务。
工作流程:
外部请求 → 节点IP:NodePort → iptables/IPVS → ClusterIP:Port → 后端Pod
核心特点:
- 每个节点都开同一个 NodePort,访问任意节点 IP 都能路由到后端 Pod
- 端口范围固定(30000-32767),不够灵活
- 无法做域名解析和 SSL 卸载,通常仅用于测试或小规模暴露
yaml
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 31000 # 可不填,K8s 自动分配
适用场景: 开发测试环境、临时对外暴露、无云厂商 LB 的裸金属环境(配合 MetalLB 使用)
3. LoadBalancer
定义: 在 NodePort 基础上,自动调用云厂商 API 创建外部四层负载均衡器,是生产环境外部流量接入的主流方式。
详见下文 三、LoadBalancer 工作原理。
4. ExternalName
定义: 不绑定 Pod,而是将 Service 映射到一个集群外部的域名,相当于 DNS 层面的 CNAME。
适用场景:
- 集群内 Pod 需要访问外部服务(如 RDS、第三方 API)
- 将外部服务"纳入"K8s 服务发现体系,便于后续迁移
yaml
spec:
type: ExternalName
externalName: db.example.com # 外部 DNS 域名
注意: 不会创建 ClusterIP,也不会代理流量,纯粹是 DNS CNAME 映射。
5. Headless Service
定义: 将 clusterIP 显式设为 None,不分配虚拟 IP,DNS 查询直接返回所有后端 Pod 的 IP 列表。
适用场景: StatefulSet(MySQL 主从、Kafka 集群),客户端需要直接感知每个 Pod 的 IP 和 hostname
yaml
spec:
clusterIP: None
selector:
app: mysql
DNS 解析:mysql-0.my-svc.default.svc.cluster.local → Pod 实际 IP
6. 五种类型对比速查
| 类型 | 集群内访问 | 外部访问 | 典型场景 |
|---|---|---|---|
| ClusterIP | ✅ | ❌ | 微服务内部调用 |
| NodePort | ✅ | ✅(节点IP:端口) | 开发测试 |
| LoadBalancer | ✅ | ✅(云LB IP) | 生产对外暴露 |
| ExternalName | ✅(DNS映射) | ❌ | 访问外部服务 |
| Headless | ✅(直连Pod) | ❌ | StatefulSet |
三、LoadBalancer 工作原理
LoadBalancer 是 K8s 最常用的外部暴露方式,涉及云控制器管理器(CCM)、NodePort、kube-proxy 多个组件协同工作。
1. 完整流量链路
外部用户
│
▼
云厂商 LB(外部IP,四层转发)
│ 后端:集群所有节点IP + NodePort
▼
节点:NodePort
│ kube-proxy iptables/IPVS 规则
▼
ClusterIP(虚拟IP)
│
▼
健康 Pod
2.真实案例
这里是前端web的一个service案例:
yaml
apiVersion: v1
kind: Service
metadata:
name: yituweb-nginx-svc
namespace: dx-test
spec:
clusterIP: 172.29.13.104
clusterIPs:
- 172.29.13.104
externalTrafficPolicy: Local
ports:
- name: yituweb-service
nodePort: 30080
port: 23343
protocol: TCP
targetPort: 23343
selector:
app: yituweb
sessionAffinity: None
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 10.49.49.66

3. 创建流程(五步)
3.1 创建 Service
用户提交 type: LoadBalancer 的 Service YAML,K8s 自动为其分配 ClusterIP 和 NodePort。
3.2 CCM 监听并调用云 API
云控制器管理器(Cloud Controller Manager)监听到 Service 创建事件,调用云厂商 API(如阿里云 SLB、AWS ELB)创建四层负载均衡器实例。
3.3 LB 后端注册节点
CCM 将集群所有节点的 IP 和分配的 NodePort 注册为 LB 后端,并配置健康检查策略。
3.4 LB IP 写回 Service
云 LB 创建完成后,CCM 将 LB 的公网 IP 写回到 Service 的 status.loadBalancer.ingress[].ip 字段,kubectl get svc 就能看到 EXTERNAL-IP。
3.5 流量进入集群
外部请求到达 LB,LB 按轮询等策略转发到节点的 NodePort,再由 kube-proxy 转发到后端 Pod。
4. 健康检查机制
LB 并非盲目转发,它会通过两层机制确保只转发到健康节点和健康 Pod:
4.1 节点级健康检查
LB 定期探测节点 IP:NodePort,无响应的节点会被自动踢出后端列表。
4.2 Pod 级过滤
kube-proxy 通过 EndpointSlice 维护健康 Pod 列表(通过 Readiness Probe 判断),未就绪的 Pod 不会出现在 Endpoints 里,LB 流量不会转到故障 Pod。
5. externalTrafficPolicy 参数
这是 LoadBalancer 里一个容易踩坑的关键参数:
| 值 | 行为 | 优缺点 |
|---|---|---|
Cluster(默认) |
任意节点接收流量后,可能再转发到其他节点的 Pod | 负载均匀,但会多一跳,源IP丢失 |
Local |
只转发到当前节点上存在 Pod 的节点 | 保留源IP,减少网络跳数,但负载可能不均 |
生产建议: 对需要获取真实客户端 IP 的场景(如安全审计、限流),使用 Local;其他场景默认 Cluster。
yaml
spec:
type: LoadBalancer
externalTrafficPolicy: Local
5. 自建环境怎么用 LoadBalancer?
裸金属或自建 K8s 环境没有云厂商 API,用 MetalLB 替代:
- MetalLB 分配 IP 池,监听 Service 创建
- 通过 Layer2 或 BGP 模式宣告 IP 路由
- 效果等同于云 LB,但依赖本地网络设备支持
四、Service 与 Ingress 的区别
很多人会混淆 Service LoadBalancer 和 Ingress,这里专门厘清:
| 维度 | Service LoadBalancer | Ingress |
|---|---|---|
| 层级 | 四层(TCP/UDP) | 七层(HTTP/HTTPS) |
| 域名路由 | ❌ 不支持 | ✅ 支持 |
| SSL 卸载 | ❌ | ✅ |
| 一个IP对多服务 | ❌(每个Service一个LB) | ✅ |
| 依赖 | 云厂商LB | Ingress Controller(如Nginx) |
实际生产架构: 通常是 云LB → Ingress Controller Pod(NodePort/LoadBalancer)→ Ingress 规则 → 各业务 Service(ClusterIP)→ Pod,两者配合使用。
五、总结
1. 五种类型选型口诀
集群内访问用 ClusterIP
测试对外用 NodePort
生产对外用 LoadBalancer
外部服务映射用 ExternalName
有状态应用直连用 Headless
2. LoadBalancer 核心记忆点
- 创建链路: 提交Service → CCM调用云API → 创建外部LB → IP写回Service
- 流量路径: 云LB → NodePort → iptables/IPVS → Pod
- 健康保障: LB健康检查(节点级)+ EndpointSlice(Pod级)双重保险
- 重要参数:
externalTrafficPolicy: Local保留源IP
3. 速查命令
bash
# 查看 Service 状态和 EXTERNAL-IP
kubectl get svc -n <namespace>
# 查看 Service 详情(含 Endpoints)
kubectl describe svc <svc-name>
# 查看 EndpointSlice(健康Pod列表)
kubectl get endpointslice -n <namespace>
# 查看 kube-proxy 的 iptables 规则
iptables -t nat -L KUBE-SERVICES -n | grep <svc-name>
# 查看 IPVS 规则(如果使用 IPVS 模式)
ipvsadm -Ln | grep <clusterIP>