1. 程式人生 > >CNCF CNI系列之三:flannel vxlan模式工作原理淺析

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: <NO-CARRIER,BROADCAST,MULTICAST,UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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協議的封裝:


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