CNCF CNI系列之三:flannel vxlan模式工作原理浅析

一、前言

flannel为container提供网络解决方案。flannel有一个基于etcd cluster的数据交换中心,每个节点上有flannel service,每个节点被分配不同的网段,每个节点上的container从该网段获取IP。一个节点之间通过一个overlay网络保证container可以互联互通。

转载自https://blog.csdn.net/cloudvtech

二、flannel的系统结构

在控制层面,flannel有一个基于etcd cluster的被动式控制中心,存储IP地址段的分配信息;所有节点上的flannel service仅仅通过更新etcd上的数据进行信息交换,没有任何主动式的相互通信。所以可以把flannel看作一个准分布式系统,所有节点上的状态都是本节点的flannel service进行维护。节点上flannel service的所有动作都是基于ectd上面数据的变化,比如节点增删等等。

在数据层面,每个节点上的flannel service都会根据本机的flannel配置进行数据包的封装或者路由的设置;flannel也会借助bridge CNI plugin或者docker engine对container进行网络设置(包括container内部网络和必要的宿主机网络)。


在数据层面,flannel支持基于路由的互联方案如host-gw、AliVPC、AWS VPC、GCE和基于封装的路由方案如UDP封装、vxlan封装、IPIP和IPSec等。

转载自https://blog.csdn.net/cloudvtech

三、flannel在etcd上的初始配置

flannel运行需要在etcd上面设置初始的网络配置如下:

{

  "Network": "172.22.0.0/16",
  "SubnetLen": 24,
  "Backend": {
    "Type": "vxlan"
   }
 } 

通过etcdctl mk /test/network/config "{ \"Network\": \"172.22.0.0/16\", \"SubnetLen\": 24, \"Backend\": { \"Type\": \"vxlan\" } }" 

来在etcd里面设置初始的配置

每个节点都感知其它节点的存在:

etcdctl ls /test/network --recursive
/test/network/config
/test/network/subnets
/test/network/subnets/172.22.9.0-24
/test/network/subnets/172.22.21.0-24
/test/network/subnets/172.22.90.0-24
可以查看具体某个节点的配置信息如下:
etcdctl get /test/network/subnets/ 172.22.9.0-24
{"PublicIP":"192.168.166.102","BackendType":"vxlan","BackendData":{"VtepMAC":"1a:9a:e1:c1:be:3f"}}
 

每个节点会感知系统里面子网分配的变化并调整相关封装参数或者路,而对于所有加入flannel的节点和container来讲,flannel给它们呈现的是一个flat的/16大三层网络,每个节点获取里面一个/24的网段。

转载自https://blog.csdn.net/cloudvtech

四、flannel在node上的配置

node上的flannel service在启动的时候,会以如下的方式运行:

/usr/bin/flanneld -etcd-endpoints=http://192.168.166.101:4001 -etcd-prefix=/test/network


启动之后,会从etcd读取flannel的配置信息,获取一个subnet,并开始监听etcd数据的变化。flanneld还会配置相关backend并将信息写入/run/flannel/subnet.env

FLANNEL_NETWORK=172.22.0.0/16
FLANNEL_SUBNET=172.22.9.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false

将docker daemon的配置信息写入 /run/flannel/docker 

DOCKER_OPT_BIP="--bip=172.22.9.1/24"
DOCKER_OPT_IPMASQ="--ip-masq=true"
DOCKER_OPT_MTU="--mtu=1450"
DOCKER_NETWORK_OPTIONS=" --bip=172.22.9.1/24 --ip-masq=true --mtu=1450"

在启动之后,flanneld会在node上面创建一个flannel.1的vxlan设备并将节点对应的子网赋给docker0(由)

3: docker0:  mtu 1500 qdisc noqueue state DOWN 

    link/ether 02:42:e0:e9:e9:52 brd ff:ff:ff:ff:ff:ff

    inet 172.22.9.1/24 scope global docker0

       valid_lft forever preferred_lft forever

4: flannel.1:  mtu 1450 qdisc noqueue state UNKNOWN 

    link/ether 1a:9a:e1:c1:be:3f brd ff:ff:ff:ff:ff:ff

    inet 172.22.9.0/32 scope global flannel.1

       valid_lft forever preferred_lft forever

    inet6 fe80::189a:e1ff:fec1:be3f/64 scope link 

       valid_lft forever preferred_lft forever

并且生成如下的路由:

ip route

default via 192.168.166.2 dev ens33 proto static metric 100 

172.22.0.0/16 dev flannel.1 

172.22.9.0/24 dev docker0 proto kernel scope link src 172.22.9.1 

192.168.166.0/24 dev ens33 proto kernel scope link src 192.168.166.102 metric 100 

并且根据flannel使用模式的不同如CNI插件方式(借助CNI bridge plugin)或者service方式(修改docker daemon启动参数,-bip),flannel会将container挂载到相应的bridge上面,并在container里面配置相应路由。

转载自https://blog.csdn.net/cloudvtech

五、flannel数据流(vxlan模式)

如果在container内访问另外一个container内的服务(IP:172.22.21.2),数据包的流程如下。

1.container内的路由

数据包从container的网络协议栈出发,container的路由如下:

# docker exec a12d 
ip route
default via 172.22.9.1 dev eth0 
172.22.9.0/24 dev eth0 scope link  src 172.22.9.2


根据路由,需要经由default路由进入eth0

数据包eth0进入container挂载的bridge,bridge看到基于IP路由到来的数据包,发现需要进行路由中继,于是为该数据包选择下一跳。

2.主机上的路由

根据主机上的路由表ip route

default via 192.168.166.2 dev ens33 proto static metric 100 

172.22.0.0/16 dev flannel.1 

172.22.9.0/24 dev docker0 proto kernel scope link src 172.22.9.1 

192.168.166.0/24 dev ens33 proto kernel scope link src 192.168.166.102 metric 100 

这个目的IP为172.22.21.2包会选择default路由从而进入flannel.1 vxlan设备。这个flannel.1是一个vtep(virtual tunnel end point)设备,它的IP地址是172.22.9.0,所以这个数据包需要继续进行转发。

3.vxlan的封装

由于flannel.1是一个vtep二层设备,所以需要根据vxlan的协议标准进行二层封装转发。而二层转发的前提是需要获取远程对应IP172.22.21.2的节点的mac地址,由于vxlan设备在查询的mac的时候是不会发送arp信息的,所以这时候flanneld可以从ectd里面获取目的IP所在网段对应的vtep设备的mac地址:

etcdctl get /test/network/subnets/ 172.22.21.0-24

{"PublicIP":"192.168.166.103","BackendType":"vxlan","BackendData":{"VtepMAC":"4a:32:0c:c6:57:77"}}


这时候,linux内核就可以获取目的地IP172.22.21.2对应的vxlan设备的mac地址4a:32:0c:c6:57:77,并进行基于vxlan协议的封装:

CNCF CNI系列之三:flannel vxlan模式工作原理浅析_第1张图片

4. vxlan的转发

在数据包经由vxlan规范封装之后,内核需要知道将这个vxlan包送到哪个节点去。所以需要查询本节点上的vxlan fdb(forwarding database)以获得目的端vtep对应的IP地址,如果未能查询到则flanneld需要向ectd查询并存储到fdb中。这时候vxlan设备就能准确的将数据包经由UDP协议发送至对端的vxlan设备flannel.1了:

bridge fdb show dev flannel.1
4e:99:73:dd:7a:f2 dst 192.168.166.104 self permanent
52:78:6a:a3:74:40 dst 192.168.166.103 self permanent

5. vxlan的解包

对端节点接受到数据包之后,会识别出这是一个vxlan的封包,并将包交给对应的vtep设备flannel.1,再经由bridge传送给container。

转载自https://blog.csdn.net/cloudvtech

你可能感兴趣的:(container,容器,网络,容器网络,kubernetes,CNI)