在上一篇文章里我们介绍了k8s集群中flannel vxlan overlay网络的创建,这在里我们基于上一篇文章中的例子,来介绍在flannel vxlan overlay网络中pod到pod的通讯。
查看集群中所有的pod:
我们用以前文章里部署的nginx application为例子,对于这个应用:
有2个pod,10.1.55.2和10.1.74.5
pod 10.1.55.2,在host 172.20.11.42上
pod 10.1.74.5,在host 172.20.11.43上
从10.1.55.2访问10.1.74.5,ping或者traceroute来验证pod间的通讯。
kubectl get pods -o wide --all-namespaces

利用以前文章中的kubectl-debug进入pod 10.1.55.2调试:
kubectl-debug deployment-nginx-app-69b6bbfd6d-5k8pd --namespace default

从pod 10.1.55.2访问pod 10.1.74.5
ip addrping -c 4 10.1.74.5ip addrtraceroute 10.1.74.5


发现无论是ping命令还是traceroute命令都可以从pod 10.1.55.2访问的到pod 10.1.74.5,说明flannel vxlan overlay网络是没有问题的。
我们分析数据是如何从pod 10.1.55.2访问的到pod 10.1.74.5的
数据在pod network namespace的路由:
根据以前文章,ip为10.1.55.2的pod从自己的network namespace访问pod 10.1.74.5,根据10.1.55.2 pod network namespace的路由表,数据进入了10.1.55.2 pod的宿主172.20.11.42的network namespace中的linux bridge docker0。
数据在宿主network namespace的路由:
ip addr|grep 42route -n

我们发现10.1.74.0/24网段的访问下一跳ip地址是10.1.74.0/32,并且用flannel.1设备发送。而这个flannel.1设备就是flannel启动的时候根据vxlan类型网络在宿主上创建的,它属于vxlan设备,会完成对二层eth以太数据包到udp数据包的封装与拆封。其中的".1"代表vxlan这个二层网络id号为1,也对应了vxlan网络在etcd里的配置。这个时候数据包源ip为10.1.55.2,目标ip为10.1.74.5,源mac为pod 10.1.55.2 network namespace中veth设备mac,目标mac为下一跳ip 10.1.74.0/32的mac。
查询vtep端点mac地址:
我们在pod 10.1.55.2的宿主172.20.11.42上通过arp表查询10.1.74.0/32的mac地址为5e:75:7d:bf:98:03
ip addr|grep 42ip neigh|grep 10.1.74.0ip neigh show dev flannel.1

查询vtep端点mac地址转发接口:
由于flannel.1设备是vxlan设备,会有转发接口与它的mac对应,我们继续在pod 10.1.55.2的宿主172.20.11.42上查询flannel.1设备的mac转发接口。
ip addr|grep 42bridge fdb show |grep 5e:75:7d:bf:98:03bridge fdb show dev flannel.1

我们发现flannel.1设备mac地址5e:75:7d:bf:98:03对应的转发接口为172.20.11.43,代表flannel.1设备将会把原始二层数据包(源ip为10.1.55.2,目标ip为10.1.74.5,源mac为pod 10.1.55.2 network namespace中veth设备mac,目标mac为10.1.74.0/32 mac)做为upd的payload发给172.20.11.43的8472端口(上一篇文章有端口配置)。而我们知道目标pod 10.1.74.5的宿主确实是172.20.11.43,而且其上的flannel.1设备同样会对8472端口的数据进行upd解包。
flannel.1设备upd封包:
ip addr|grep 42route -n

我们从pod 10.1.55.2的宿主172.20.11.42的路由表得知发往172.20.11.0/24网段为直连路由,使用宿主网络设备enp0s3发送。所以对于:
外层udp包:源ip为172.20.11.42,目标ip为172.20.11.43,源mac为172.20.11.42 mac,目标mac为172.20.11.43 mac。目标端口为8472,vxlan id为1.
内层二层以太包:源ip为10.1.55.2,目标ip为10.1.74.5,源mac为pod 10.1.55.2 network namespace中veth设备mac,目标mac为10.1.74.0/32 mac
完成封包以后根据宿主路由表发向目标节点172.20.11.43。
目标节点处理upd封包:
目标节点172.20.11.43的8472端口接收到udp包之后,发现数据包里有vxlan id标识为1。由于linux内核支持vxlan,所以协议栈可以通过vxlan id判断这是一个vxlan数据报文,并且vxlan为1。然后找到宿主机器上vxlan id为1的vxlan设备处理,这里就是172.20.11.43上的flannel.1设备了。
flannel.1收到数据之后开始对vxlan udp报文拆包,去掉upd报文的ip,port,mac信息后得到内部的payload,发现是一个二层报文。
对于这个二层报文继续拆包,得到里面的源ip是10.1.55.2,目标ip是10.1.74.5。
根据172.20.11.43上路由表,将数据由linux bridge docker0做本地转发。

根据以前文章,docker0作为linux bridge利用veth pair将数据转发到目标pod 10.1.74.5。
host的路由表和fdb转发表的写入:
这里vxlan关键的两个点就是:
宿主host的路由表的写入
flannel.1设备mac转发接口表的写入
那么这些数据是怎么写入host的呢?因为所有的host都运行flannel服务,而flannel连接etcd存储中心,所以每个host就知道自己的子网地址cidr是什么,也知道在这个cidr中自己的flannel.1设备ip地址和mac地址,同时也知道了其它host的子网cidr以及flannel.1设备ip地址和mac地址。而知道了这些信息,就可以在flannel启动的时候写入到路由表和fdb中了,以下面172.20.11.42宿主为例:
ip addr|grep 42bridge fdb show dev flannel.1etcdctl --ca-file etc/etcd/ca.crt --cert-file etc/etcd/etcd-client.crt --key-file etc/etcd/etcd-client.key get cloudnetwork/subnets/10.1.82.0-24etcdctl --ca-file etc/etcd/ca.crt --cert-file /etc/etcd/etcd-client.crt --key-file /etc/etcd/etcd-client.key get /cloudnetwork/subnets/10.1.74.0-24etcdctl --ca-file /etc/etcd/ca.crt --cert-file /etc/etcd/etcd-client.crt --key-file /etc/etcd/etcd-client.key get /cloudnetwork/subnets/10.1.55.0-24

总结flannel vxlan overlay网络pod到pod的通讯过程如下:
每个宿主都有名字为flannel.x的vxlan网络设备来完成对于vxlan数据的udp封包与拆包,upd数据在宿主的8472端口上(端口值可配置)处理。
数据从pod的network namespace进入到host的network namespace中。
根据host network namespace中的路由表,下一跳ip为目标vxlan设备的ip,并且由当前host的flannel.x设备发送。
根据host network namespace中的apr表找到下一跳ip的mac地址。
根据host network namespace中fbd找到下一跳ip的mac地址对应的转发ip。
当前host的flannel.x设备根据下一跳ip的mac地址对应的转发ip和本地路由表进行upd封包,这个时候:
外层udp包:源ip为当前host ip,目标ip为mac转发表中匹配的ip,源mac为前host ip的mac,目标mac为fdb中匹配ip的mac。目标端口为8472(可配置),vxlan id为1(可配置).
内层二层以太包:源ip为源pod ip,目标ip为目标pod ip,源mac为源pod mac,目标mac为host network namespace中路由表里下一跳ip的mac(一般为目标pod对应的host中flannel.x设备ip)。
数据包由当前host路由到目标节点host。
目标节点host的8472端口接收到udp包之后,发现数据包里有vxlan id标识.。然后根据linux vxlan协议,在目标宿主机器上找到与数据报文中vxlan id对应的vxlan设备,将数据交由其处理。
vxlan设备收到数据之后开始对vxlan udp报文拆包,去掉upd报文的ip,port,mac信息后得到内部的payload,发现是一个二层报文。然后继续对这个二层报文拆包,得到里面的源pod ip和目标pod ip。
根据目标节点host上路由表,将数据由linux bridge docker0做本地转发。
数据由linux bridge docker0利用veth pair转发到目标pod。
每个宿主host的flannel服务启动的时候读取etcd中的vxlan配置信息,在宿主host的路由表和mac转发接口表fdb里写入相应数据。
目前先写到这里,下一篇文章里我们继续介绍k8s集群中基于flannel upd方式的overlay网络setup。





