Skip to content
容器高级2025-01-15·阅读约 1 分钟

Service / Ingress 不通排障(2025-01-15) ​

现象 ​

外部访问网站超时。集群内 Pod 互相访问 ClusterIP 也偶发不通。Service 已创建、后端 Pod 也 Running,但流量就是到不了容器。

text
# 外部
curl -I https://api.example.com
curl: (28) Failed to connect: Connection timed out

# 集群内
kubectl exec debug -- curl -I http://my-svc.default.svc.cluster.local
# 连不上

环境 ​

组件版本
Kubernetes1.31.1(kubeadm)
CNI / 网络Calico + kube-proxy(ipvs 模式)
Ingressingress-nginx controller(Controller 模式)
Servicemy-svc ClusterIP,后端是 my-app 的 Pod

定位过程 ​

1. 分层排查:从外到内逐层定位 ​

K8s 网络是多层的,按这个顺序逐层测:

层级命令不通说明
① Pod 直接访问kubectl exec <pod> -- curl localhost:8080应用本身没起来
② 同节点另一 Pod 访问 PodIPcurl <PodIP>:8080CNI 网络不通
③ 跨节点访问 PodIPcurl <PodIP>:8080跨节点路由/Calico 问题
④ ClusterIP 访问curl <ClusterIP>kube-proxy/iptables 问题
⑤ Service DNS 解析nslookup my-svcCoreDNS 问题
⑥ Ingress 访问curl -H Host: xxx http://<ingress-ip>Ingress 规则问题

2. 第一步:看 Service 有没有正确选中 Endpoints ​

这是最常见的坑——Service selector 选不中 Pod,Endpoints 是空的:

bash
kubectl get svc my-svc
kubectl get endpoints my-svc

如果 ENDPOINTS 列是 <none>,说明 selector 没匹配到任何 Pod:

bash
# 对比 Service 的 selector 和 Pod 的 labels
kubectl get svc my-svc -o yaml | grep -A5 selector
kubectl get pods --show-labels

本次发现:Service selector 写的是 app=my-app, version=v1,但 Pod 实际 label 是 app=my-app, version=v2——标签对不上,Endpoints 为空。

3. Endpoints 正常但 ClusterIP 不通:查 kube-proxy ​

bash
# 看 kube-proxy 是否正常
kubectl -n kube-system get pods | grep kube-proxy
# 在节点上看 ipvs 规则有没有这条 service
ipvsadm -ln | grep <ClusterIP>

4. Ingress 层:规则有没有配对 ​

bash
kubectl get ingress
kubectl describe ingress my-ingress
# 看 BACKEND 是不是正确的 service:port

# 看 ingress controller 日志
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=50

常见 Ingress 坑:

  • host 域名和实际访问域名对不上。
  • path 路径和后端不匹配(/api vs /api/)。
  • ingress-nginx 没安装/没监听。

根因 ​

层级说明
直接原因Service 的 selector 与后端 Pod labels 不一致,导致 Endpoints 为空,流量无后端可转发
流程原因发布后改了 Pod label 但没同步改 Service selector

解决步骤 ​

止血 ​

  1. 修正 selector,让 Service 选中正确的 Pod:
bash
kubectl edit svc my-svc
# selector:
#   app: my-app
#   version: v2      # 改成 Pod 实际的 label
  1. 验证 Endpoints 立刻有了后端:
bash
kubectl get endpoints my-svc
# 应显示 PodIP:port 列表

根治 ​

  1. 规范 label 管理:应用 label 与 Service selector 纳入 code review;推荐用 Helm/Kustomize 统一管理 label。

  2. Ingress 排查时确认 host/path 与后端匹配,必要时用 curl 带 Host 头直连 ingress controller IP 定位:

bash
curl -I -H "Host: api.example.com" http://<ingress-controller-ip>/healthz
  1. 链路加就绪探针:Pod 没就绪不会进 Endpoints,避免流量打到还没准备好的容器。

验证与预防 ​

bash
kubectl get endpoints my-svc          # 非空
kubectl exec debug -- curl http://my-svc   # 通
curl -I https://api.example.com       # 外部通
  • 监控:Service Endpoints 为空告警(选中后端数=0 时报警)。
  • 排障套路:从 PodIP → ClusterIP → Ingress 逐层测,先看 Endpoints 再查 kube-proxy。
  • 规范:label selector 变更要同步检查 Service。

相关 ​