VOL. 02 — NETWORKING

网络与服务
排查手册

THE OPS FIELD MANUAL
Service · Ingress · DNS · CNI

Production Edition
Service 不通 DNS 解析失败 Ingress 502 NetworkPolicy 跨节点不通 NodePort

K8s 网络是洋葱式的:容器内 → veth → CNI → kube-proxy iptables/ipvs → Service → DNS → Ingress → 外部。任何一层出问题,流量都过不去。排查的本质是从内向外逐层 ping/curl,定位断点在哪一层。

01
CONTAINER
Pod 内进程
02
CNI
Calico / Flannel
03
SERVICE
kube-proxy
04
DNS
CoreDNS
05
INGRESS
外部入口
01

Service ClusterIP 不通,curl 没响应

SERVICE → ENDPOINT → POD CHAIN BROKEN
高频 必会
  • Pod A 访问 Service B 的 ClusterIP,超时或 connection refused
  • 但直接 curl Pod B 的 IP 能通
  • 有时是间歇性失败(只通一部分请求)
# 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>
最常见的坑 · Service 的 targetPort 必须和 Pod 实际监听端口一致,而不是和 Service 自己的 port 一致。port: 80, targetPort: 8080 的意思是:Service 在 80 端口接收,转发到 Pod 的 8080。

Service 不通快速决策树

  1. Endpoints 为空? → selector 写错 / Pod label 不对 / Pod 未 Ready
  2. Endpoints 有 IP 但不通? → targetPort 写错 / Pod 防火墙
  3. 有时通有时不通? → 多副本中某个 Pod 异常,readiness 没踢掉
  4. 跨命名空间不通? → 必须用 FQDN svc.ns.svc.cluster.local
02

DNS 解析失败,nslookup 超时

COREDNS RESOLUTION FAILURE
高频 必会
  • Pod 内 ping 域名失败,但 ping IP 没问题
  • nslookup 超时或返回 SERVFAIL
  • 应用日志 "Temporary failure in name resolution"
# 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.prodprod 命名空间的 mysql跨 ns 必须加 ns 名
mysql.prod.svc.cluster.localFQDN 完整路径最稳,跨集群也认
baidu.com外部域名CoreDNS forward 到上游
性能坑 · resolv.conf 里 ndots:5 会导致每次查外部域名先按 search 后缀拼接 5 次再才查根域,大量无效 DNS 请求。高 QPS 业务用 FQDN(末尾加点) baidu.com. 跳过搜索域。
临时绕过 CoreDNS · 紧急情况下可以给 Pod 配 dnsPolicy: None + dnsConfig.nameservers: [114.114.114.114],直接走外部 DNS 隔离问题。
03

Ingress 返回 502 / 503 / 504

UPSTREAM CONNECTION FAILURE
高频 必会
状态码含义常见原因
502 Bad Gateway上游返回了无效响应后端 Pod 崩了,或返回的不是 HTTP
503 Unavailable后端没有可用 PodEndpoints 为空,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"  # 大文件上传必须调
HTTPS 后端的坑 · 如果后端是 HTTPS 服务,需要加 annotation:nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"。不加的话,Ingress 用 HTTP 访问 HTTPS 后端,会 502。
04

跨节点 Pod 通信失败

CNI / OVERLAY NETWORK BROKEN
中频 高级
  • 同节点 Pod 之间互通,跨节点不通
  • 跨节点 ping 超时或丢包严重
  • 新节点加入后,上面的 Pod 网络不通
  • CNI 插件 Pod 在某节点没运行(DaemonSet 异常)
  • 节点之间 BGP/VXLAN 端口被防火墙拦截
  • 路由表错误(Pod CIDR 配置不一致)
  • MTU 不匹配(VXLAN 封装 +50 字节,容易超限)
# 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
云上特殊情况 · 阿里云/AWS 等云环境,跨可用区或跨子网时,云厂商安全组可能拦截 Pod CIDR 流量。需要在安全组放行 Pod 网段。
05

NodePort 外部访问不通

EXTERNAL → NODEPORT → SERVICE
高频 入门
  • 节点防火墙拦截 NodePort 端口(默认 30000-32767)
  • 云服务器安全组未放行端口
  • kube-proxy 异常,iptables 规则没下发
  • 访问的不是节点的对外 IP(如阿里云内网 IP)
# 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>
externalTrafficPolicy 的影响 · 默认值 Cluster:NodePort 流量会被随机转发到任意节点的 Pod,源 IP 会被 SNAT 丢失。Local:只转发到本节点 Pod,保留源 IP,但需要每个节点都有该 Pod。
06

NetworkPolicy 误伤业务

DEFAULT DENY MISCONFIGURATION
中频 高级
  • 配置了"默认拒绝所有"策略,但忘了放行 DNS(53 端口),所有 Pod DNS 失效
  • egress 策略限制了出站,但应用要访问外部 API
  • 同命名空间没放行,导致同 ns 内 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
调试技巧 · Calico 提供 calicoctl get networkpolicy 看更详细规则;开启 Calico 的 log action 能看到具体哪条规则拦截了流量。
07

Endpoints 列表为空

SELECTOR / READINESS MISMATCH
高频 入门
  • Pod label 和 Service selector 不一致(最常见,90%)
  • Pod 没有 Ready — readinessProbe 失败的 Pod 不会进 Endpoints
  • Service 的 namespace 和 Pod 不在同一个 ns
# 一条命令对比 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 段
08

kube-proxy 异常,Service 全员失效

CRITICAL CLUSTER COMPONENT FAILURE
低频 致命
  • 整个集群所有 Service 都不通
  • 但 Pod 直接 IP 访问正常
  • iptables 没有 KUBE-SVC- 开头的规则
# 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
对比项iptablesipvs
性能规则线性匹配,Service 多了变慢哈希表 O(1),性能高
负载均衡算法仅 randomrr / lc / sh / dh 多种
规则数量每个 Service 数十条每个 Service 一条
适用规模< 1000 Service大规模生产
切换模式 · 修改 kube-proxy ConfigMap 的 mode: ipvs,重启 kube-proxy。注意 ipvs 模式需要节点加载 ip_vs, ip_vs_rr, nf_conntrack 等内核模块。