1. Flannel的host-gw模式
Flannel的host-gw模式是一种纯三层的网络互通方案,Pod之间互相访问是通过路由方式实现。host-gw模式下跨节点网络通信需要通过节点上的路由表实现,因此必须要通信双方所在宿主机能够直接路由。这就要求该模式下集群中所有节点必须处于同一个网络内。公有云环境下需要安装对应的插件,如阿里云的CCM。
2. host-gw模式下的组网
flannel host-gw模式下涉及的主要网络设施有:
- veth pair
- cni0网桥
- 物理网卡
- 路由表
我们从Pod A出发,去探寻组网方式。首先,进入Pod A的网络namespace中查看Pod A的路由
[root@cn-beijing ~]# ip route
default via 10.10.2.1 dev eth0
10.10.0.0/16 via 10.10.2.1 dev eth0
10.10.2.0/24 dev eth0 proto kernel scope link src 10.10.2.238
Pod A的包都是通过eth0发送给10.10.2.1这个IP。到这里就出现两个问题:
- 10.10.2.1这个IP是谁?
- eth0是如何连接到10.10.2.1这个设备?
退出Pod A的网络namespace,通过指令查看主机上的设备的IP地址
[root@cn-beijing ~]# ip a
...
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 2e:5b:e9:3d:88:51 brd ff:ff:ff:ff:ff:ff
inet 10.10.2.1/24 brd 10.10.2.255 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::2c5b:e9ff:fe3d:8851/64 scope link
valid_lft forever preferred_lft forever
...
可以发现10.10.2.1为cni0网桥的地址。那么Pod A是如何连接到cni0网桥上的呢。
再次进入Pod A的网络namespace查看Pod A内的eth0网卡的类型
[root@cn-beijing ~]# ip -d link show eth0
3: eth0@if2270: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 86:41:d0:e3:0c:65 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0
veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
发现eth0是一个veth设备的一端,到eth0的对端veth设备编号为2270(@if2270)。
回到Node A的主网络namespace查找2270编号的网络设备
[root@cn-beijing ~]# ip a
...
2270: vethef2d98bc@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cni0 state UP group default
link/ether 5e:14:e7:9e:ca:fd brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::5c14:e7ff:fe9e:cafd/64 scope link
valid_lft forever preferred_lft forever
...
可以看到编号为2270的网络设备为vethef2d98bc,并且是挂在在网桥cni0上的(master cni0)。到此,可以发现Pod A就是通过veth pair设备连接到cni0网桥上的。
host-gw模式下,每个node节点都是一个独立的网段,这个网段配置在cni0网桥上。如图Node A的Pod网段为10.10.2.1/24,cni0网桥的IP为10.10.2.1,是这个网桥上挂载的所有Pod的默认网关。
那下面我们继续探寻Pod A的网络请求发送到cni0后会是如何流转的出去的。
3. 图解host-gw模式下包流转
从上一节的讨论可以看到,ICMP报文通过路由、veth设备发送到了cni0网桥上,网桥收到报文后应该如何处理呢?
为了能够抓到流转方式,我们打开iptables的TRACE功能。从Node A和Node B上执行如下命令
[root@cn-beijing ~]# iptables -t raw -A OUTPUT -p icmp -j TRACE
[root@cn-beijing ~]# iptables -t raw -A PREROUTING -p icmp -j TRACE
上述命令打开TRACE功能后,包的流转信息就会被记录在/var/log/messages文件里。
我们进入Pod A的网络命名空间执行ping(为了方便分析,我们只ping 1次)
[root@cn-beijing ~]# ping 10.10.3.4 -c 1
PING 10.10.3.4 (10.10.3.4) 56(84) bytes of data.
64 bytes from 10.10.3.4: icmp_seq=1 ttl=62 time=0.747 ms
--- 10.10.3.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.747/0.747/0.747/0.000 ms