面向初级运维,使用 Linux 节点和稳定 Kubernetes API。命令按 Bash 编写。本文为教学故障场景,日志及结果为示意,不冒充生产实测;执行前确认 context、命名空间和权限。
一、遭遇情况:Pod 明明正常,访问 Service 却失败
应用 Pod Ready,容器日志也正常,但同命名空间客户端请求 Service 超时或连接失败。有人准备重启 kube-proxy,实际可能只是 Service selector 写错。
本篇场景是 Pod 标签为 app: web,Service 却选择 app: web-typo。Service 对象创建成功,也分配到 ClusterIP,但没有匹配的业务后端。
二、原因分析:Service 对象存在,不代表流量有落点
带 selector 的 Service 根据命名空间内匹配的 Pod 形成后端,EndpointSlice 表达这些端点及条件。Pod 存在、标签匹配、端点就绪和目标端口正确,缺一项都可能影响访问。

port 是访问 Service 使用的端口,targetPort 指向后端应用端口;containerPort 是声明信息,不会替应用自动启动监听。不要把这三个字段当作同一个“端口号”。
三、排查思路:先验证应用,再验证抽象层
kubectl get pods -n 目标命名空间 -o wide --show-labels
kubectl get service 目标服务 -n 目标命名空间 -o yaml
kubectl get endpointslice -n 目标命名空间 -l kubernetes.io/service-name=目标服务 -o yaml
把占位名称替换为实际值。核对 Service selector 与 Pod 标签是否一字不差;EndpointSlice 不只看 IP,还要看 ready 等条件、端口与目标对象。常规业务应优先检查 EndpointSlice,不把旧 Endpoints 输出当作唯一依据。
在同一类客户端环境中比较 Pod IP 与 Service 名/IP:直接 Pod 也失败,先看应用、CNI 或策略;Pod 成功而 Service 失败,再查选择、端口和数据路径。ClusterIP 通常从集群内部访问,不要用外部电脑直接访问失败作为唯一证据。
四、实践:一个 selector 拼错的最小服务
保存为 kt09-service.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: kt09
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: kt09
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:stable-alpine
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
path: /
port: http
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: kt09
spec:
selector:
app: web-typo
ports:
- name: http
port: 80
targetPort: http
kubectl apply -f kt09-service.yaml
kubectl rollout status deployment/web -n kt09 --timeout=120s
kubectl run client -n kt09 --image=busybox:1.37 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/client -n kt09 --timeout=120s
kubectl get endpointslice -n kt09 -l kubernetes.io/service-name=web -o yaml
kubectl exec client -n kt09 -- wget -T 3 -qO- http://web:80/
预期 Service 没有匹配的可用后端,请求失败,具体失败方式由集群网络实现决定。再直接请求实际 Web Pod:
pod_ip=$(kubectl get pod -n kt09 -l app=web -o jsonpath='{.items[0].status.podIP}')
kubectl exec client -n kt09 -- wget -T 3 -qO- "http://$pod_ip:80/"
若基础网络及策略允许,直接请求应返回 Nginx 页面,这将故障进一步限定在 Service 相关层。
五、修复实践:只修错误选择器
kubectl patch service web -n kt09 --type=merge -p '{"spec":{"selector":{"app":"web"}}}'
kubectl get endpointslice -n kt09 -l kubernetes.io/service-name=web -o yaml
kubectl exec client -n kt09 -- wget -T 3 -qO- http://web:80/
预期匹配到 Ready 的 Web 后端,并获得页面响应。控制器更新需要时间,刚打完补丁仍失败时应观察端点是否已经更新,不必立即重启整个网络组件。
如果后端存在而访问失败,再核对 targetPort、应用监听、NetworkPolicy,以及 kube-proxy 或集群采用的其他 Service 数据面。不是所有集群都用同一套 iptables 规则,不要直接套用清空规则的命令。
六、port-forward 为什么可能让人误判
kubectl port-forward service/web 本机端口:服务端口 会选择关联 Pod 建立诊断转发,不等于从客户端经过 ClusterIP 的完整路径。因此 port-forward 成功,能支持“某个后端应用可响应”,不能单独证明 Service VIP 转发正常。
七、验证与总结
在故障原来的客户端条件下,再验证 Service 名、ClusterIP 与业务响应。确认新 Pod 扩缩容后端仍正确,修复也已写回部署源文件。
这类故障应从应用、selector、端点条件和端口逐层走向数据面。先证明配置链路完整,再怀疑集群组件,往往能避免影响全局的误操作。