Kubernetes (K8S) 网络原理

Pod 间通信

在 Kubernetes 中,Pod 间通信是网络模型的核心部分。本页将详细介绍同一节点上不同 Pod 之间的通信机制,以及实现这种通信的底层技术。

Pod 间通信示意图

Pod 间通信基本原理

Kubernetes 的网络模型基于以下几个关键原则:

在同一节点上的 Pod 间通信是最简单的情况,通常通过以下组件实现:

同节点 Pod 间通信详解

通信流程

当同一节点上的 Pod A 需要与 Pod B 通信时,数据包的流动路径如下:

  1. 数据包从 Pod A 的网络命名空间中的 eth0 接口发出
  2. 数据包通过 veth pair 到达主机网络命名空间
  3. 数据包到达主机上的网桥(如 cbr0、cni0 或 docker0)
  4. 网桥根据目标 MAC 地址将数据包转发到正确的 veth 接口
  5. 数据包通过 veth pair 到达 Pod B 的网络命名空间
  6. 数据包到达 Pod B 的 eth0 接口,并被传递到应用程序

这个过程是标准的二层网络转发,不需要 NAT 或复杂的路由。

veth pair
网桥
ARP 和 MAC 地址
路由表

虚拟以太网设备对(veth pair)

veth pair 是 Linux 网络虚拟化的基础组件,它创建了一对虚拟网络接口,这对接口的特点是:

  • 一端连接到容器(Pod)的网络命名空间
  • 另一端连接到主机的网络命名空间
  • 从一端发送的数据包会立即出现在另一端
  • 可以将它们想象为一根虚拟的"网线",连接两个网络命名空间
# 查看主机上的 veth 接口 ip link | grep veth # 查找特定 Pod 对应的 veth 接口 POD_IP=$(kubectl get pod -o jsonpath='{.status.podIP}') bridge fdb | grep $POD_IP

每个 Pod 都有一个 veth pair,一端在 Pod 内部显示为 eth0,另一端在主机上显示为类似 vethXXXXXX 的接口名称。

Linux 网桥

网桥是一个虚拟的二层网络设备,它学习 MAC 地址并相应地转发数据包。在 Kubernetes 中:

  • 每个节点通常有一个网桥(如 cbr0、cni0 或 docker0)
  • 所有 Pod 的 veth 接口都连接到这个网桥
  • 网桥维护一个 MAC 地址表,记录每个接口的 MAC 地址
  • 当数据包到达网桥时,它根据目标 MAC 地址决定转发到哪个接口
# 查看主机上的网桥 ip link show type bridge # 查看网桥上连接的接口 bridge link show # 查看网桥的 MAC 地址表 bridge fdb show

网桥的作用类似于物理网络中的交换机,它使得连接到它的所有 Pod 都位于同一个二层网络中。

ARP 和 MAC 地址

当 Pod A 需要与 Pod B 通信时,它需要知道 Pod B 的 MAC 地址。这是通过 ARP(地址解析协议)实现的:

  1. Pod A 知道 Pod B 的 IP 地址(如 10.244.1.3)
  2. Pod A 发送 ARP 请求:"谁拥有 IP 10.244.1.3?"
  3. 这个 ARP 请求通过 veth pair 到达网桥
  4. 网桥将 ARP 请求广播到所有连接的接口
  5. Pod B 收到 ARP 请求并回复自己的 MAC 地址
  6. Pod A 收到回复,缓存 Pod B 的 MAC 地址
  7. 后续通信直接使用已知的 MAC 地址
# 查看 Pod 的 ARP 缓存 kubectl exec -it -- ip neigh # 查看主机的 ARP 缓存 ip neigh

路由表

虽然同一节点上的 Pod 通信主要依靠网桥进行二层转发,但路由表仍然起着重要作用:

  • 主机的路由表告诉内核如何处理目标为 Pod 网络的数据包
  • 通常会有一条路由规则,将 Pod 子网的流量导向网桥
  • Pod 内部的路由表通常很简单,只有默认路由指向 eth0
# 查看主机的路由表 ip route # 查看 Pod 的路由表 kubectl exec -it -- ip route

典型的主机路由表可能包含类似以下的条目:

10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1

这表示目标为 10.244.1.0/24 网段的数据包应该发送到 cni0 接口(网桥)。

不同 CNI 插件的实现差异

虽然基本原理相似,但不同的 CNI 插件在实现同节点 Pod 间通信时可能有一些差异:

Flannel

Flannel 使用相对简单的方式实现同节点 Pod 通信:

  • 创建一个名为 cni0 的网桥
  • 为每个 Pod 创建 veth pair,一端连接到 Pod,另一端连接到 cni0
  • 为 cni0 分配节点的 Pod 子网中的第一个 IP 地址(如 10.244.1.1)
  • 配置路由,使得 Pod 子网的流量通过 cni0

Flannel 的同节点通信非常高效,因为它只涉及简单的二层转发。

Calico

Calico 在同节点 Pod 通信中使用了不同的方法:

  • 默认情况下,Calico 不使用网桥,而是使用路由表
  • 每个 Pod 的 veth 接口直接连接到主机网络命名空间
  • 为每个 Pod 添加一条主机路由,将 Pod IP 指向对应的 veth 接口
  • 使用 Linux 内核的转发功能而不是网桥进行数据包转发

这种方法减少了一层网络设备(网桥),可能提供更好的性能,但配置更复杂。

注意:Calico 也可以配置为使用网桥模式。

Weave Net

Weave Net 的同节点通信实现:

  • 创建一个名为 weave 的网桥
  • 为每个 Pod 创建 veth pair,连接 Pod 和 weave 网桥
  • 使用自定义的数据路径优化性能
  • 支持加密通信,即使是同节点 Pod 之间

Weave Net 的一个特点是它的"fast datapath"模式,可以提高同节点通信的性能。

Pod 间通信的性能考虑

同节点 Pod 间通信通常非常高效,但仍有一些性能因素需要考虑:

影响性能的因素

性能优化建议

# 测试 Pod 间网络性能 kubectl run iperf-server --image=networkstatic/iperf3 --port=5201 -- iperf3 -s kubectl run iperf-client --image=networkstatic/iperf3 --rm -it -- iperf3 -c iperf-server

故障排除

在 Pod 间通信中可能遇到的常见问题及解决方法:

连接问题

症状:Pod 无法连接到同节点上的其他 Pod

可能原因:

  • 网络策略阻止了通信
  • 路由配置错误
  • ARP 缓存问题
  • CNI 插件配置错误

排查步骤:

# 检查连通性 kubectl exec -it -- ping # 检查路由 kubectl exec -it -- ip route ip route # 检查 ARP 缓存 kubectl exec -it -- ip neigh ip neigh # 检查网络策略 kubectl get networkpolicies

性能问题

症状:Pod 间通信延迟高或吞吐量低

可能原因:

  • 节点资源(CPU/内存)不足
  • 网络拥塞
  • MTU 配置不当
  • 内核参数限制

排查步骤:

# 检查节点资源使用情况 kubectl top nodes # 检查 MTU kubectl exec -it -- ip link show eth0 ip link show cni0 # 使用 iperf3 测试网络性能 kubectl exec -it -- iperf3 -c # 检查丢包 kubectl exec -it -- ping -c 100

CNI 插件问题

症状:Pod 网络配置失败或行为异常

排查步骤:

# 检查 CNI 配置 ls -la /etc/cni/net.d/ # 检查 CNI 插件日志 journalctl -u kubelet | grep cni # 检查 CNI 相关 Pod 的状态 kubectl get pods -n kube-system -l k8s-app=calico-node kubectl logs -n kube-system -l k8s-app=calico-node

相关资源

要了解更多关于 Pod 间通信的信息,可以参考以下资源:

了解跨节点 Pod 通信