K8s 客户端与 Pod 连接跟踪:各模式原理与排查命令

适用版本:Kubernetes 1.23+(conntrack bypass 参数有所变化),Calico/Cilium/IPVS
⚠️:有些地方需要验证


一、先搞懂一个核心问题

外部客户端与集群内 Pod 建立连接时,ss/netstat 看不到完整信息,原因是 "两边都不在同一层网络"

  • 客户端所在网络,与 Pod 网络通常不在同一二层

  • Pod 的连接不绑定宿主机端口,ss 无法感知

  • 真正看到连接状态的入口是 conntrack(走了 NAT 的情况)或 各模式自己的连接表


二、快速对照表

模式

走 conntrack?

客户端能否看到 Pod IP

查看命令

iptables

✅ 必走

❌ 被 SNAT 隐藏

conntrack -L -p tcp

IPVS + NAT/SNAT

✅ 走

部分隐藏

conntrack -L + ipvsadm -lnc

IPVS + Full-NAT (conntrack bypass)

❌ 绕过

❌ 双向 SNAT

ipvsadm -lnc + cilium bpf

Cilium eBPF socket LB

❌ 绕过

✅ 真实 IP 直通

cilium-dbg bpf sock list + hubble


三、iptables 模式

3.1 原理

Client(10.0.0.5:任意端口)
    │
    ▼
NodeIP:NodePort(192.168.1.100:30080)
    │
    ▼ kube-proxy 创建的 iptables DNAT 规则
    │  prerouting → KUBE-SVC-xxxxx → KUBE-SEP-xxxxx
    │
    ▼ [conntrack 记录 DNAT]
PodIP:PodPort(10.244.1.20:8080)     ← 源 IP 被 SNAT 为 NodeIP
    │
    ▼ [conntrack 回程匹配 SNAT]
返回包 → 自动还原为 ClientIP:端口

关键点:

  • iptables 在 PREROUTING / OUTPUT 做 DNAT(目的地址转换)

  • POSTROUTING 做 SNAT(源地址伪装)

  • 所有转换记录在 conntrack 表

  • 出去和回来的包都经过 conntrack 查询匹配

3.2 查看连接的完整方案

# 在 Node 上查看所有活跃连接(最常用)
conntrack -L -p tcp -n

# 查看访问某个 NodePort 的所有连接
conntrack -L -p tcp --dport 30080 -n

# 查看某个客户端 IP 的所有连接记录
conntrack -L -p tcp -s 10.0.0.5 -n

# 查看访问某个 ClusterIP 的连接
conntrack -L -p tcp -d 10.244.0.1 -n

# 统计当前 conntrack 表条目数量
conntrack -C

# 查看 conntrack 表容量上限(满了会导致丢包!)
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count

# 如果有 conntrack_WARN 日志,说明连接数逼近上限
dmesg | grep conntrack

3.3 conntrack 查看结果解读

tcp  6 115  ESTABLISHED src=10.244.0.5  dst=10.244.1.20  sport=45678 dport=8080 src=10.244.1.20  dst=10.0.0.5  sport=8080 dport=45678 [ASSURED]
  • src/dst = 客户端视角(原始请求方向)

  • src/dst(第二组)= Pod 视角(经过 DNAT+SNAT 后的方向)

  • [ASSURED] = 连接正常,双向有流量

  • [UNREPLIED] = 只发过 SYN,未确认或已断开

3.4 iptables 规则查看(了解谁在动)

# 查看 KUBE-SERVICES 链(所有 Service 入口)
iptables -t nat -L KUBE-SERVICES -n --line

# 查看某个 Service 的 DNAT 规则
iptables -t nat -L KUBE-SVC-xxxxx -n -v

# 查看 SNAT(伪装)规则
iptables -t nat -L KUBE-POSTROUTING -n -v

四、IPVS 模式

4.1 两种子模式:是否绕过 conntrack

IPVS 本身是内核中的负载均衡模块(基于哈希表,性能远优于 iptables 链式匹配)。 kube-proxy IPVS 模式分为两种情况:

4.1.1 IPVS + conntrack(默认 / Masquerade 模式)

Client → NodeIP:NodePort → IPVS(DNAT) → Pod
                                        │
                              conntrack(SNAT) → 回程匹配
  • kube-proxy 参数 --masquerade-all=true 或逐 Service 设置 --masquerade-bit

  • IPVS 只做第一次 DNAT 分配

  • 回程流量由 conntrack 处理 SNAT

  • conntrack 中可见完整连接

# 查看 IPVS Service 定义
ipvsadm -ln

# 查看 IPVS 连接的 session 表(IPVS 自己维护的连接)
ipvsadm -lnc

# 查看统计
ipvsadm -ln --stats

# 查看经过 IPVS 端口的 conntrack 条目
conntrack -L -p tcp --dport <NodePort> -n

4.1.2 IPVS + Full-NAT(conntrack bypass 模式)

从 Kubernetes 1.23 版本起,支持 --ipvs-conntrack-bypass 参数(实验性):

Client → NodeIP:NodePort
           │
      IPVS(DNAT+SNAT)   ← IPVS 同时做源目转换,不调用 conntrack
           │
        PodIP:PodPort
           │
      直接回包(IPVS SNAT 还原源 IP)

关键点:

  • IPVS 在转发时同时做 source NAT,Pod 直接用原始 Client IP 发回响应

  • 不需要 conntrack 介入回程处理

  • conntrack 表中看不到 Service→Pod 这段的连接

  • 性能更好,避免了 conntrack 的性能开销

# 查看 IPVS session 表(核心手段)
ipvsadm -lnc

# 仍可以看到客户端到 NodePort 入口的连接
ss -ant | grep :<NodePort>

# Pod 侧:exec 进入 Pod 查看
kubectl exec -it <pod> -- ss -ant

# tcpdump 在主机网卡抓包验证
tcpdump -i eth0 host <ClientIP> and tcp port <ServicePort> -nn

# 查看 IPVS 统计确认流量经过
ipvsadm -ln --stats | grep <ServiceIP>

4.2 IPVS 模式连接状态解读

tcp  00:57:09 ESTABLISHED 10.244.0.5:45678 10.244.1.20:8080

这是 ipvsadm -lnc 的输出:

  • 左边是客户端 IP(未经过 NAT 的原始 IP)

  • 右边是 Pod IP(经过 IPVS DNAT 后的目标)

  • ESTABLISHED 说明连接活跃


五、Cilium eBPF 模式

5.1 原理

Cilium 完全替代 kube-proxy,使用 eBPF sockmap/sockhash 在 socket 层做负载均衡:

Client Pod → ClusterIP
    │
eBPF Socket LB(内核侧拦截 connect/bind)
    │
直接路由到目标 Pod(无 NAT)
    │
Pod 直接回包给 Client(真实 IP)

关键点:

  • 零 NAT:客户端 IP 和 Pod IP 端到端保持原样

  • 零 conntrack:数据包路径完全不经过 conntrack

  • 在 socket 创建时就完成了负载均衡选择(比 iptables/IPVS 更早)

  • 性能最高,支持 FALLBACK(部分流量降级到 iptables)

5.2 查看连接的完整方案

方式一:Cilium agent 命令(最推荐)

# 进入 Cilium agent Pod
kubectl exec -it -n kube-system <cilium-pod> -- /bin/bash

# 查看所有 BPF socket 映射(类似 conntrack 表)
cilium-dbg bpf sock list

# 查看 Service → backend 的负载均衡映射
cilium-dbg bpf lb list

# 查看端点(所有 Pod)
cilium-dbg endpoint list

# 查看 conntrack 表(Cilium 自己的,如果不走 conntrack 则为空)
cilium-dbg bpf ct list

# 查看详细状态
cilium-dbg status --verbose

方式二:直接用 ss(Pod 内)

# 进入 Pod,直接用 ss 查看,这个是最直观的
kubectl exec -it <namespace>/<pod> -- ss -ant

# 对端就能看到真实 IP 了
# State   Recv-Q  Send-Q   Local Address:Port   Peer Address:Port
# ESTAB   0       0        10.244.0.5:45678     10.244.1.20:8080
#                        ↑ 客户端 IP(真实)

方式三:Hubble 可观测性(最强大)

# 查看 Pod 发出的所有流量
kubectl exec -it -n kube-system <cilium-pod> -- \
  hubble observe --from pod default/nginx-pod --to-port 80

# 查看特定 IP 的流量
kubectl exec -it -n kube-system <cilium-pod> -- \
  hubble observe --ip 10.244.1.20

# 查看某个 Service 的所有流量
kubectl exec -it -n kube-system <cilium-pod> -- \
  hubble observe --to service default/my-service

方式四:宿主机上查看(需 privileged)

# 在宿主机上查看 BPF socket map(需要 Cilium CLI)
cilium bpf sock list

# 查看 BPF conntrack(如果有)
cilium bpf ct list

# tcpdump 抓包验证(两端 IP 都能看到)
tcpdump -i cilium_host host <ClientIP> and host <PodIP> -nn

5.3 Cilium 模式下的 conntrack

# 在 Cilium 替换 kube-proxy 后,conntrack 通常为空
conntrack -L -p tcp -n | wc -l

# 如果仍看到条目,说明有些流量降级走了 iptables
conntrack -L -p tcp -n | grep <ServiceIP>

# Cilium 状态确认
cilium-dbg status | grep -i conntrack
cilium-dbg status | grep -i kubeProxyReplacement

六、实战排查流程图

发现连接问题(访问慢 / 连接不上 / 丢包)
    │
    ▼
这是什么类型的流量?
    │
    ├─ ClusterIP(集群内部)→ 查看 Pod 内的 ss
    │
    ├─ NodePort(外部访问)
    │      │
    │      ▼
    │  什么代理模式?
    │      │
    │      ├─ iptables → conntrack -L -p tcp --dport <NodePort>
    │      │
    │      ├─ IPVS → ipvsadm -lnc + conntrack -L
    │      │
    │      └─ Cilium → cilium-dbg bpf sock list + hubble observe
    │
    └─ LoadBalancer(云商入口)→ 查云商控制台 + NodePort 手段

七、通用排查命令速查表

场景

推荐命令

任意模式下,查看 Pod 内部连接

kubectl exec -it <pod> -- ss -ant

iptables 模式,查看 Service 连接

conntrack -L -p tcp -d <ClusterIP> -n

IPVS 模式,查看 Session

ipvsadm -lnc

Cilium 模式,查看 Socket

cilium-dbg bpf sock list

Cilium 模式,追踪流量

hubble observe --from pod <ns/pod>

任意模式,抓包验证

tcpdump -i <iface> host <PodIP> -nn

查看 conntrack 表大小

conntrack -C + cat /proc/sys/net/netfilter/nf_conntrack_max

查看 iptables 规则

iptables -t nat -L -n --line

查看 IPVS 规则

ipvsadm -ln

确认当前 kube-proxy 模式

kubectl get configmap kube-proxy -n kube-system -o yaml


八、各模式连接生命周期对比

阶段

iptables

IPVS+conntrack

IPVS+FullNAT

Cilium

入口匹配

iptables PREROUTING

IPVS

IPVS

eBPF sockmap

目的转换

conntrack DNAT

IPVS DNAT

IPVS DNAT+SNAT

无(直接路由)

源转换

iptables SNAT

conntrack SNAT

IPVS SNAT

回程匹配

conntrack

conntrack

IPVS 自己处理

conntrack 表

✅ 有记录

✅ 有记录

❌ 无记录

❌ 无记录

Pod 看到的客户端 IP

NodeIP(被 SNAT)

NodeIP(被 SNAT)

原始 ClientIP

原始 ClientIP

性能

⭐⭐

⭐⭐⭐

⭐⭐⭐⭐

⭐⭐⭐⭐⭐