Kubernetes Service 访问不通的三层深度排查
在 Kubernetes 生产环境中,“Service 访问不通”是一个发生频次极高、排查链路横跨多个网络层级的复杂故障。很多初级工程师在遇到curl order-service:8080报错Connection refused或i/o timeout时,往往陷入迷茫,只能盲目地重启 Pod 或重启节点。
Kubernetes 的 Service 并不是一个物理实体,它本质上是由 DNS 解析、APIServer 端点控制器、以及节点内核网络规则(iptables / IPVS)共同编织出的一层分布式虚拟负载均衡网络。
要快速定位 Service 访问不通的根因,必须建立起一套严密的**“DNS 解析层 → 控制面 Endpoint 发现层 → 数据面内核数据包转发层”**三层排查链条。
[ 客户端 Pod 发起: curl order-service:8080 ] │ ▼ (第一层排查: CoreDNS 域名解析) [ CoreDNS 是否正确返回 ClusterIP: 10.96.12.34 ? ] │ (是) ▼ (第二层排查: 控制面 Endpoint 挂载) [ Endpoints / EndpointSlice 是否包含健康的 Pod IP ? ] │ (是) ▼ (第三层排查: 数据面内核转发规则) [ 宿主机 iptables / IPVS 规则与 CNI 网络插件是否正常 ? ] │ (是) ▼ [ 成功到达目标 Pod ]第一层排查:CoreDNS 域名解析与 ndots 机制
当客户端使用服务名(如order-service)发起请求时,首先依赖 CoreDNS 完成域名到 ClusterIP 的解析。
1. 排查诊断命令
# 登录排障客户端 Pod kubectl exec -it debug-pod -n prod -- sh # 1.1 直接测试 DNS 解析 nslookup order-service.prod.svc.cluster.local # 1.2 若解析超时,直接测试能否解析 CoreDNS 自身 dig @10.96.0.10 order-service.prod.svc.cluster.local +short2. 常见故障点与根因
- CoreDNS 自身高负载或挂掉:检查
kubectl get pods -n kube-system -l k8s-app=kube-dns,确认 CoreDNS 副本是否处于 Running 状态,无 OOMKilled。 /etc/resolv.conf的ndots:5放大效应:由于默认ndots:5,每次查询短域名都会在prod.svc.cluster.local、svc.cluster.local、cluster.local之间递归追溯 4 次以上,高并发下导致 CoreDNS 被打爆。在客户端引入完整 FQDN 域名或配置 NodeLocal DNSCache 即可解决。
第二层排查:控制面 Endpoint 关联与就绪探针
如果 DNS 能够成功解析出 ClusterIP(如10.96.12.34),但curl该 IP 依然报错Connection refused,说明问题出在控制面的 Pod 端点发现阶段。
1. 排查诊断命令
# 检查 Service 关联的 Endpoints 与 EndpointSlice kubectl get endpoints order-service -n prod kubectl get endpointslice -l kubernetes.io/service-name=order-service -n prod # 检查 Service 的 Label Selector kubectl get svc order-service -n prod -o jsonpath='{.spec.selector}'2. 常见故障点与根因
- Label Selector 标签不匹配:Service 的
spec.selector拼写错误(如app: order-svc误写为app: order-service),导致没有匹配到任何底层 Pod,ENDPOINTS显示为<none>。 - 就绪探针(Readiness Probe)失败:Pod 虽然处于
Running状态,但由于健康检查接口返回 500 或超时,K8s 判定其尚未就绪,主动将该 Pod 的 IP 从 Endpoints 列表中剔除。必须通过kubectl describe pod <pod_name>查看 Readiness 事件。 - 端口映射错位(Port vs TargetPort):Service 的
port是 Service 暴露的虚拟端口,而targetPort必须严格等于容器进程实际监听的物理端口。
第三层排查:数据面 iptables / IPVS 内核转发与 CNI 插件
如果 Endpoints 列表里存在健康的 Pod IP(例如10.244.1.45:8080),直接curl 10.244.1.45:8080正常,但curl 10.96.12.34:8080(通过 ClusterIP)却不通,说明问题出在节点内核的kube-proxy数据转发层。
1. 排查诊断命令
登录客户端 Pod 所在物理宿主机:
# 1.1 若 kube-proxy 为 IPVS 模式: 查看虚拟服务器与真实 Real Server 映射 ipvsadm -ln | grep -A 3 "10.96.12.34" # 1.2 若 kube-proxy 为 iptables 模式: 检查 KUBE-SERVICES 链 iptables -t nat -L KUBE-SERVICES -n -v | grep "10.96.12.34" # 1.3 查看 kube-proxy 组件日志 kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=1002. 常见故障点与根因
kube-proxy发生死锁或崩溃:由于 APIServer 压力大,kube-proxy与 APIServer 的 Watch 连接中断,未能及时同步最新的网络规则。- Linux 内核
bridge-nf-call-iptables被关闭:在某些节点初始化脚本中,若未设置sysctl -w net.bridge.bridge-nf-call-iptables=1,二层网桥流量不会经过 iptables 规则链,导致 ClusterIP 的 NAT 地址转换彻底失效。 - 跨主机 CNI 隧道丢包(Calico / Flannel MTU 错位):如果物理宿主机网络 MTU 为 1500,而 Calico VXLAN 隧道网卡 MTU 也设为 1500,封装后的外层报文超过 1500 且开启了禁止分片(DF),大包跨主机传输时会被网卡静默丢弃。必须将 CNI 网卡 MTU 调小为
1450(预留 50 字节头部开销)。
总结
排查 Kubernetes Service 访问故障,绝不能无目的地乱试。
严格遵循**“先看 DNS 能否出 IP → 再看 Endpoints 是否挂着 Pod → 最后下沉到宿主机看 IPVS 转发与 MTU”**的三层诊断路径,任何复杂的网络断连问题都能在 3 分钟内精准定位根因。