K8s 网络是洋葱式的:容器内 → veth → CNI → kube-proxy iptables/ipvs → Service → DNS → Ingress → 外部。任何一层出问题,流量都过不去。排查的本质是从内向外逐层 ping/curl,定位断点在哪一层。
# Step 1. Service 是否存在,selector 是什么 kubectl get svc <svc-name> -o yaml | grep -A 3 selector # Step 2. Endpoints 是否有 IP(关键!没 IP 就是 selector 没匹配上) kubectl get endpoints <svc-name> # 输出 ENDPOINTS 列为 <none> → selector 和 Pod label 对不上 # Step 3. Pod 的 label 是不是和 selector 一致 kubectl get pod --show-labels | grep <app> # Step 4. Service 端口和 Pod containerPort 是否匹配 kubectl describe svc <svc> kubectl describe pod <pod> | grep -i port # Step 5. 直接测 Service ClusterIP kubectl run debug --rm -it --image=nicolaka/netshoot -- bash # 进入后: curl <service-name>.<namespace>.svc.cluster.local curl <cluster-ip>:<port>
targetPort 必须和 Pod 实际监听端口一致,而不是和 Service 自己的 port 一致。port: 80, targetPort: 8080 的意思是:Service 在 80 端口接收,转发到 Pod 的 8080。
svc.ns.svc.cluster.local# 1. 测试 Pod 内 DNS kubectl run dnsdebug --rm -it --image=nicolaka/netshoot -- bash # 进入后 nslookup kubernetes.default nslookup baidu.com cat /etc/resolv.conf # 应该看到 nameserver 是 10.96.0.10(默认 CoreDNS Service IP) # 2. 检查 CoreDNS Pod 状态 kubectl -n kube-system get pod -l k8s-app=kube-dns kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50 # 3. 检查 CoreDNS Service kubectl -n kube-system get svc kube-dns # 4. 检查 CoreDNS 配置(常见问题:forward 上游 DNS 不通) kubectl -n kube-system get cm coredns -o yaml
| 查询写法 | 实际解析 | 说明 |
|---|---|---|
mysql | 同 ns 的 mysql svc | 短名,只能同命名空间 |
mysql.prod | prod 命名空间的 mysql | 跨 ns 必须加 ns 名 |
mysql.prod.svc.cluster.local | FQDN 完整路径 | 最稳,跨集群也认 |
baidu.com | 外部域名 | CoreDNS forward 到上游 |
ndots:5 会导致每次查外部域名先按 search 后缀拼接 5 次再才查根域,大量无效 DNS 请求。高 QPS 业务用 FQDN(末尾加点) baidu.com. 跳过搜索域。
dnsPolicy: None + dnsConfig.nameservers: [114.114.114.114],直接走外部 DNS 隔离问题。
| 状态码 | 含义 | 常见原因 |
|---|---|---|
502 Bad Gateway | 上游返回了无效响应 | 后端 Pod 崩了,或返回的不是 HTTP |
503 Unavailable | 后端没有可用 Pod | Endpoints 为空,Pod 都没 Ready |
504 Gateway Timeout | 后端响应超时 | 应用慢、Ingress proxy 超时太短 |
# 1. 看 Ingress Controller 日志(最关键) kubectl -n ingress-nginx logs -l app.kubernetes.io/name=ingress-nginx --tail=100 # 2. Ingress 规则是否正确 kubectl describe ingress <name> # 3. 后端 Service 的 Endpoints 是否健康 kubectl get endpoints <backend-svc> # 4. 跳过 Ingress 直接测 Service,定位是 Ingress 还是后端 kubectl port-forward svc/<backend-svc> 8080:80 curl localhost:8080
# 通过 annotation 调整 nginx-ingress 超时 metadata: annotations: nginx.ingress.kubernetes.io/proxy-connect-timeout: "60" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-body-size: "50m" # 大文件上传必须调
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"。不加的话,Ingress 用 HTTP 访问 HTTPS 后端,会 502。
# 1. 检查所有节点的 CNI Pod kubectl -n kube-system get pod -o wide | grep -E "calico|flannel" # 2. Calico 检查节点状态 calicoctl node status # 应看到所有节点 BGP peer 是 Established # 3. 节点防火墙(Calico BGP 用 179, Flannel VXLAN 用 8472) iptables -nL | grep "179\|8472" firewall-cmd --list-all # CentOS # 4. MTU 检查(节点间能通的最大包) ping -M do -s 1472 <other-node-ip> # Calico VXLAN 默认 MTU 1450,要小于物理网卡 50 字节 # 5. 路由表是否包含其他节点的 Pod CIDR ip route | grep tunl # 应看到类似: 10.244.1.0/24 via 192.168.1.11 dev tunl0
# 1. 看 NodePort 端口 kubectl get svc <svc> # 输出形如 80:31234/TCP, 31234 就是 NodePort # 2. 节点上看端口监听 ss -lntp | grep 31234 # 注意: NodePort 不是真的监听端口,iptables/ipvs 转发,可能看不到 # 3. 节点本机测试 curl localhost:31234 curl <node-internal-ip>:31234 # 4. 检查防火墙 iptables -nL -t nat | grep 31234 firewall-cmd --add-port=31234/tcp --permanent firewall-cmd --reload # 5. iptables 规则是否生成(kube-proxy 是否正常) iptables-save | grep <svc-name>
Cluster:NodePort 流量会被随机转发到任意节点的 Pod,源 IP 会被 SNAT 丢失。Local:只转发到本节点 Pod,保留源 IP,但需要每个节点都有该 Pod。
# 1. 查看命名空间下所有 NetworkPolicy kubectl get networkpolicy -A # 2. 看具体规则 kubectl describe networkpolicy <name> -n <ns> # 3. 临时禁用某个策略测试 kubectl delete networkpolicy <name> -n <ns>
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-dns namespace: default spec: podSelector: {} # 应用到 ns 下所有 Pod policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 - protocol: TCP port: 53
calicoctl get networkpolicy 看更详细规则;开启 Calico 的 log action 能看到具体哪条规则拦截了流量。
# 一条命令对比 selector 和 label kubectl get svc <svc> -o jsonpath='{.spec.selector}'; echo kubectl get pods --show-labels | grep <app> # 检查 Pod 是否 Ready(NotReady 不会进 endpoints) kubectl get pod -o wide # READY 列必须是 1/1 才会被纳入 endpoints # readinessProbe 失败的临时绕过(测试用,生产慎用) kubectl edit deploy <name> # 临时删掉 readinessProbe 段
# 1. 看 kube-proxy Pod kubectl -n kube-system get pod -l k8s-app=kube-proxy -o wide # 2. 看日志 kubectl -n kube-system logs -l k8s-app=kube-proxy --tail=100 # 3. 检查 iptables 规则 iptables-save | grep KUBE-SVC | head iptables-save | grep KUBE-NODEPORTS | head # 4. ipvs 模式下检查转发表 ipvsadm -Ln | head # 5. 重启 kube-proxy(DaemonSet 滚动重启) kubectl -n kube-system rollout restart daemonset kube-proxy
| 对比项 | iptables | ipvs |
|---|---|---|
| 性能 | 规则线性匹配,Service 多了变慢 | 哈希表 O(1),性能高 |
| 负载均衡算法 | 仅 random | rr / lc / sh / dh 多种 |
| 规则数量 | 每个 Service 数十条 | 每个 Service 一条 |
| 适用规模 | < 1000 Service | 大规模生产 |
mode: ipvs,重启 kube-proxy。注意 ipvs 模式需要节点加载 ip_vs, ip_vs_rr, nf_conntrack 等内核模块。