1. 初识Kubernetes Pod网络

刚接触Kubernetes时,最让我困惑的就是:为什么每个Pod都有自己的IP地址?这些IP地址是怎么分配的?不同节点上的Pod又是如何互相通信的?经过多次实践踩坑后,我发现理解Pod网络需要从最基础的虚拟网络设备说起。

在传统物理机时代,服务器之间通过网线和交换机连接。而在Kubernetes的虚拟化世界里,veth pair就是我们的"虚拟网线",docker0/cni0就是"虚拟交换机"。每个Pod启动时,都会创建一对veth虚拟网卡,一端放在Pod的网络命名空间里(显示为eth0),另一端连接到宿主机的网桥上。这就好比给每个Pod插上了网线,连接到同一台交换机。

我曾在测试环境做过一个实验:创建一个nginx Pod,进入容器执行ifconfig,果然看到了eth0网卡:

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.244.1.5  netmask 255.255.255.0  broadcast 10.244.1.255

而在宿主机上执行brctl show cni0,能看到对应的veth另一端:

bridge name     interfaces
cni0            veth9a8b7f1a

这种设计让Pod拥有了独立的网络栈,就像一台独立的主机。实际测试中,同一个节点上的两个Pod可以直接ping通对方的IP,延迟通常在0.1ms以内,几乎和本地通信没有区别。

2. Pod内部通信机制

很多初学者会好奇:一个Pod里多个容器是怎么共享网络的?这就要说到Kubernetes的"pause容器"设计。我曾在集群中执行docker ps,发现每个Pod都包含一个奇怪的容器:

IMAGE                    COMMAND
k8s.gcr.io/pause:3.2    "/pause"

这个看似无用的容器其实是Pod网络的基石。它启动时会创建网络命名空间和虚拟网卡,其他容器通过--net=container:pause加入这个网络空间。你可以把它想象成一套公寓的主钥匙,其他容器都是合租的房客,共享同一个网络门户。

验证这一点很简单,在同一个Pod中的两个容器里分别执行:

# 容器1
nc -l 8080

# 容器2
telnet localhost 8080

连接会立即建立,因为它们在同一个网络栈内。但要注意端口冲突问题——就像合租时不能两个人同时用洗手间。我曾踩过坑,在Pod的两个容器里同时监听80端口,导致后启动的容器报错"address already in use"。

3. 同节点Pod通信原理

同一节点上的Pod通信,就像连接在同一台交换机上的电脑。docker0/cni0网桥就是这个虚拟交换机,所有Pod的veth端都插在上面。当Pod A(10.244.1.5)访问Pod B(10.244.1.6)时:

  1. 数据包从Pod A的eth0发出,通过veth pair到达网桥
  2. 网桥学习到Pod B的MAC地址,直接转发
  3. 数据包通过另一对veth到达Pod B

这个过程可以用一个真实案例说明。我在节点上创建了两个Pod,从Pod A ping Pod B时,用tcpdump抓包:

# 在cni0网桥上抓包
tcpdump -i cni0 -nn icmp

看到的结果是:

10:42:35.123456 IP 10.244.1.5 > 10.244.1.6: ICMP echo request
10:42:35.123789 IP 10.244.1.6 > 10.244.1.5: ICMP echo reply

这种二层转发效率很高,实测吞吐量能达到5Gbps以上,接近物理网卡性能。但要注意,如果节点上运行太多Pod,网桥的MAC表可能成为瓶颈。我曾遇到过一个节点的Pod间通信突然变慢,最后发现是MAC表项超过了默认限制,调整net.bridge.bridge-nf-call-iptables参数后解决。

4. 跨节点Pod通信方案

跨节点通信才是Kubernetes网络的精髓所在。根据我的经验,主流方案可以分为路由方案Overlay网络两大类,各有优缺点。

4.1 路由方案

路由方案就像现实中的邮政系统。每个节点相当于一个邮局,知道哪个IP段该往哪个节点送。我在使用Calico时,节点路由表是这样的:

10.244.1.0/24 via 192.168.0.101 dev eth0
10.244.2.0/24 via 192.168.0.102 dev eth0 

这意味着:

  • 目标为10.244.1.x的包,发给192.168.0.101节点
  • 目标为10.244.2.x的包,发给192.168.0.102节点

这种方案性能最好,实测跨节点延迟在0.3ms左右,接近物理网络延迟。但有个硬性要求:所有节点必须在同一个二层网络。我在混合云环境就踩过坑,当部分节点在AWS,部分在本地机房时,路由方案直接失效。

4.2 Overlay网络

Overlay方案就像快递打包——把Pod网络数据包封装在节点网络里传输。Flannel的VXLAN模式是个典型例子:

  1. 数据包从Pod A发出,到达cni0网桥
  2. flanneld将其封装为UDP包,通过eth0发出
  3. 目标节点的flanneld解封装,将原始包交给cni0

虽然这种方案适应性更强,但性能损耗明显。我做过性能对比测试:

  • 吞吐量:路由方案 950Mbps vs VXLAN 650Mbps
  • 延迟:路由方案 0.3ms vs VXLAN 0.8ms

在金融行业的生产环境中,我们最终选择了Calico的IPIP模式作为折中方案——它在跨网段时自动启用封装,同网段仍用直接路由。

5. 网络插件选型建议

经过多个项目的实践,我总结出网络插件选型的几个关键点:

  1. 中小规模集群:Calico BGP模式最佳,性能好且配置简单。我曾用3台物理机搭建测试集群,BGP协议自动学习路由,根本不需要额外配置。

  2. 云环境:直接使用云厂商的CNI插件,比如AWS的Amazon VPC CNI。它们通常深度集成云网络,性能最优。有个客户坚持自建Flannel,结果节点规模超过200后网络性能急剧下降,改用AWS原生插件后问题解决。

  3. 特殊需求场景

    • 需要网络策略:Calico
    • 需要多租户隔离:Weave Net
    • 超大规模集群:Cilium(基于eBPF)

记得有次给银行做POC测试,他们要求同时支持网络策略和性能监控,我们最终选择了Cilium,它的Hubble组件能提供堪比专业网络设备的流量可视性。

6. 常见问题排查经验

网络问题排查是Kubernetes运维的必修课。分享几个我总结的实用命令:

检查Pod网络配置

kubectl exec -it <pod> -- ip addr
kubectl exec -it <pod> -- route -n

检查节点路由表

ip route show

跨节点连通性测试

# 在Pod中测试
kubectl exec -it pod-a -- ping <pod-b-ip>

# 在节点上抓包
tcpdump -i eth0 -nn host <target-node-ip>

曾经有个经典案例:某个Pod突然无法访问同节点的其他Pod。通过逐层排查:

  1. Pod内ip addr显示eth0网卡消失
  2. 节点上brctl show发现veth端不见了
  3. 最终发现是有人手动删除了网桥设备

这个问题让我意识到:Kubernetes网络就像精密的钟表,任何一个零件异常都会导致整体失效。

更多推荐