返回归档
♠️Kubernetes

K8s 网络:CNI、VXLAN 与三条走包路径

CNI 造路,VTEP 过隧道,kube-proxy 只改 ClusterIP。Flannel VXLAN 里跨节点的下一跳是远端 VTEP,不是对端 Pod 的 MAC。Service 的 DNAT 发生在源节点,回程靠 conntrack。

文章目录

Kubernetes 网络先分清三件事:谁给 Pod 插网线,谁在跨节点时封包,谁把 Service VIP 翻译成 Pod IP。三者没有调用关系,只在包的路径上碰头。

  • CNI:规范 + 插件。kubelet 调它给 Pod 配 IP、veth、路由、网桥。Flannel、Calico、Cilium 都是实现。
  • VTEP:VXLAN 隧道端点。Flannel 上是 flannel.1。跨节点时把内层帧封进 UDP/4789,对端再剥开。
  • kube-proxy:看 Service / EndpointSlice,在节点上写 iptables 或 IPVS。它不负责 Pod 能否互相 ping。
组件 职责 挂了会怎样
CNI 造 Pod 网络,维护 VTEP Pod 没网,跨节点断
VTEP 封装 / 解封装 跨节点断,本机 Pod 还通
kube-proxy VIP → Pod IP Service 废,Pod 直连还在

下面用 Flannel VXLAN 走三种包。设定不变:

  • Underlay 192.168.1.0/24,Node1 192.168.1.10,Node2 192.168.1.20
  • Overlay 10.244.0.0/16,Node1 是 10.244.0.0/24,Node2 是 10.244.1.0/24
  • Pod-A 10.244.0.2,Pod-C 同节点 10.244.0.3,Pod-B 在 Node2 10.244.1.2
  • Service demo-svc ClusterIP 10.96.100.10,后端只有 Pod-B
  • VTEP 设备都是 flannel.1,VNI 10001,UDP 4789

同节点:只有 cni0

Pod-A 和 Pod-C 在同一个 /24。ARP 广播能直接问到对端 MAC。帧出 eth0,进 cni0 网桥,从另一条 veth 进 Pod-C。没有封装,kube-proxy 不在场。

Same node: Pod-A ARP via cni0 to Pod-C, L2 forward on the host bridge, no VXLAN

主机路由里,本机 Pod 网段指向 cni0。只有目的地址落到别的节点的 /24,才会进 flannel.1

跨节点:下一跳是远端 VTEP

这里容易写成「Pod-A ARP 问出 Pod-B 的 MAC」。Flannel VXLAN 不是一张跨节点大二层。每个节点一块 /24,跨网段是 L3

  1. Pod-A 看 10.244.1.2 不在自己网段,以太网目的 MAC 填 cni0(默认网关)。
  2. 包进 Node1 主机网络命名空间。路由类似 10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink10.244.1.0 是对端 VTEP 在 overlay 上的地址。
  3. 邻表 / FDB 给出 VTEP2 的 MAC,以及外层要送到的 Node2 192.168.1.20
  4. 内层:源 IP 仍是 Pod-A,目的 IP 仍是 Pod-B,目的 MAC 是 VTEP2。外面再套 VXLAN 头、UDP/4789、外层 IP Node1 → Node2。
  5. Underlay 只看见普通 UDP。Node2 收到后交给 flannel.1,核验 VNI,剥头,再经 cni0 送到 Pod-B。

Cross-node: Pod-A → Node1 → VTEP1 encapsulates UDP/4789 to VTEP2, then Pod-B

回程对称:VTEP2 封,VTEP1 剥。Pod 始终看不见 192.168.1.0/24。

Service:本机 DNAT 一次

生产里很少直接打 Pod IP,而是打 Service 名。

  1. Pod-A 问 CoreDNS,得到 ClusterIP 10.96.100.10
  2. 包的目的 IP 是 VIP,目的 MAC 仍是 cni0,进入 Node1。
  3. Node1PREROUTING 命中 kube-proxy 写的 KUBE-SERVICES,DNAT 成 10.244.1.2。源 IP 仍是 Pod-A。
  4. 之后和上一节完全一样:走 flannel.1,VXLAN 到 Node2,送到 Pod-B。
  5. Pod-B 回包:源 Pod-B、目的 Pod-A。隧道回到 Node1 之后,这台机器上的 conntrack 按原连接把源地址改回 VIP,再交给 Pod-A。

Service: CoreDNS → ClusterIP, Node1 netfilter DNAT to Pod-B, return conntrack rewrites src to VIP

不是 Node2 再做一次 SNAT。ClusterIP 的「看起来像访问 VIP」靠的是源节点那条连接跟踪。NodePort、从节点访问本机 Service、hairpin,才会再走到 MASQUERADE。

kube-proxy 只改这一次地址。隧道仍是 CNI 的事。两边故障域是分开的:proxy 挂了,Pod IP 直连还在。

三条 CNI,对 VXLAN 的态度不同

Flannel 默认就是这条内核 VXLAN,图简单,没有 NetworkPolicy。Calico 首选 BGP 直连,公有云不让跑 BGP 时才上 vxlan.calico,策略仍在。Cilium 用 eBPF 走封装或干脆原生路由,还能看 L7。

Flannel Calico Cilium
VXLAN 默认 Overlay BGP 不可用时的备选 eBPF 加速,可被原生路由替代
封装实现 内核 VXLAN 内核 VXLAN eBPF,少走协议栈
策略 L3/L4 L3–L7
可观察性 Hubble
更合适 小集群、先跑通 要策略的中大集群 要性能和 L7 的大规模

选型按「先要连通,再要策略,再要观测」即可。排查时先问包走的是上面三条里的哪一条:本机桥、跨节点隧道,还是先被 DNAT 再进隧道。五条链本身见 iptables