深色模式
Service 与 Endpoints 服务发现
摘要:Pod IP 会变,Service 提供稳定访问入口。本文讲清三种 Service 类型的选型、Endpoints 的自动生成机制、DNS 命名规则,以及服务访问不通时的定位步骤。
适用环境
- 可用 K8s 集群 +
kubectl - 集群已装 CNI 插件与 CoreDNS
- 示例:
nginx:alpineDeployment
操作步骤
一、为什么需要 Service
bash
kubectl get pod -o wide
kubectl delete pod <其中一个pod>
kubectl get pod -o wide # IP 已经变了1
2
3
2
3
Pod 重建后 IP 必变,直接访问 Pod IP 不可靠。Service 通过 label selector 聚合一组 Pod,对外只暴露一个稳定的 ClusterIP。
二、三种类型选型
| 类型 | 访问范围 | 典型用途 |
|---|---|---|
ClusterIP(默认) | 仅集群内 | 微服务内部互调 |
NodePort | 通过节点 IP + 端口(30000-32767) | 临时测试、无 LB 环境 |
LoadBalancer | 云厂商 LB 分配外部 IP | 生产对外暴露 |
三、创建 ClusterIP Service
yaml
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector:
app: web
ports:
- name: http
port: 80 # Service 暴露的端口
targetPort: 80 # 容器实际监听的端口
protocol: TCP1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
bash
kubectl apply -f svc.yaml
kubectl get svc web
kubectl get endpoints web # 或 kubectl get ep web1
2
3
2
3
等价的命令式写法:
bash
kubectl expose deployment web --port=80 --target-port=80 --type=ClusterIP1
四、DNS 访问规则
集群内任意 Pod 都可用以下名字访问:
bash
kubectl run test --rm -it --image=busybox --restart=Never -- sh
# 容器内:
nslookup web
nslookup web.default.svc.cluster.local
wget -qO- http://web1
2
3
4
5
2
3
4
5
完整 FQDN 格式:<service>.<namespace>.svc.cluster.local,同命名空间可省略后缀。
五、Endpoints 是怎么来的
bash
kubectl get ep web -o yaml
kubectl describe svc web1
2
2
流程:Service 定义 selector → Endpoints 控制器 watch 匹配 label 的 Pod → 把就绪的 Pod IP:Port 写入同名 Endpoints 对象 → kube-proxy 依据它生成转发规则。
注意
只有 Ready=True 的 Pod 才会进 Endpoints。Pod 起来但 readinessProbe 没过,Service 就转发不到它,表现为「时通时不通」。这是最常见的服务不通原因。
六、手动指定后端(无 selector 场景)
想让 Service 指向集群外部的数据库:
yaml
apiVersion: v1
kind: Service
metadata:
name: ext-db
spec:
ports:
- port: 3306
---
apiVersion: v1
kind: Endpoints
metadata:
name: ext-db # 必须与 Service 同名
subsets:
- addresses:
- ip: 10.0.0.50
ports:
- port: 33061
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
七、服务不通的排查顺序
bash
kubectl get svc web # 1. Service 是否存在
kubectl get ep web # 2. Endpoints 是否非空
kubectl get pod -l app=web -o wide # 3. 后端 Pod 是否 Ready
kubectl exec -it <pod> -- ss -lntp # 4. 容器内是否真的在监听端口
kubectl run test --rm -it --image=busybox --restart=Never -- nslookup web # 5. DNS1
2
3
4
5
2
3
4
5
验证
- [ ]
kubectl get ep web的 ENDPOINTS 列非空且数量等于就绪 Pod 数 - [ ] 从集群内另一 Pod 能
wget -qO- http://web拿到页面 - [ ] 删除一个 Pod 后 Endpoints 自动更新
常见坑
port与targetPort混淆:port是 Service 端口,targetPort是容器端口。容器监听 8080 却写targetPort: 80必然不通。- Endpoints 为空:selector 的 label 与 Pod 的 label 不匹配,用
kubectl get pod --show-labels核对。 - service 能解析但连接超时:kube-proxy 异常或 NetworkPolicy 拦截,检查
kubectl -n kube-system get pod -l k8s-app=kube-proxy。 - NodePort 访问不了:节点防火墙/安全组未放行 30000-32767 端口段。
- Headless Service 疑惑:设
clusterIP: None时不分配集群 IP,DNS 直接返回各 Pod IP,用于 StatefulSet,不要当成普通服务用。