一. Flannel 简介
flannel是CoreOS提供用于解决Dokcer集群跨主机通讯的覆盖网络工具。它的主要思路是:预先留出一个网段,每个主机使用其中一部分,然后每个容器被分配不同的ip;让所有的容器认为大家在同一个直连的网络,底层通过`UDP/VxLAN`等进行报文的封装和转发。
Flannel目前支持网络模式
UDP: 使用用户态udp封装,默认使用8285端口。由于是在用户态封装和解包,性能上有较大的损失
VXLAN: vxlan封装,需要配置VNI,Port(默认8472)和GBP; 是Linux内核本身支持的一种网络虚拟化技术,是内核的一个模块,在内核态实现封装解封装,构建出覆盖网络,其实就是一个由各宿主机上的Flannel.1设备组成的虚拟二层网络,由于VXLAN由于额外的封包解包,导致其性能较差;VXLAN Directrouting模式也支持类似host-gw的玩法,如果两个节点在同一网段时使用host-gw通信,如果不在同一网段中,即 当前pod所在节点与目标pod所在节点中间有路由器,就使用VXLAN这种方式,使用叠加网络
Host-gw: 直接路由的方式,将容器网络的路由信息直接更新到主机的路由表中,仅适用于二层直接可达的网络 推荐使用,效率极高
Flannel 工作模式及架构
1 UDP模式
Udp方式是Flannel项目最早支持的,也是性能最差的一种。目前已经被弃用,不过,这种方式最直接、也是最容易理解的跨主机实现。
1.1 UDP模式架构图
1.2 UDP 数据流向
1) 容器直接使用目标容器的ip访问,默认通过容器内部的eth0发送出去。
2) 报文通过veth pair被发送到vethXXX。
3) vethXXX是直接连接到虚拟交换机docker0的,报文通过虚拟bridge docker0发送出去。
4) 由表,外部容器ip的报文都会转发到flannel0虚拟网卡,这是一个P2P的虚拟网卡,然后报文就被转发到监听在另一端的flanneld。
5) flanneld通过etcd维护了各个节点之间的路由表,把原来的报文UDP封装一层,通过配置的iface发送出去。
6)报文通过主机之间的网络找到目标主机。
7) 报文继续往上,到传输层,交给监听在8285端口的flanneld程序处理。
8) 数据被解包,然后发送给flannel0虚拟网卡。
9) 查找路由表,发现对应容器的报文要交给docker0。
10) docker0找到连到自己的容器,把报文发送过去。
2 VXLAN 模式
Vxlan(Virtual eXtensible LAN),虚拟可扩展的局域网,是一种虚拟化隧道通信技术,他是一种overlay(覆盖网络)技术,通过三层的网络搭建虚拟的二层网络
Vxlan是再底层物理网络(underlay)之上使用隧道技术,依托UDP层构建的overlay的逻辑网络,使逻辑网络与物理网络解耦,实现灵活的组网需求,不仅能使适配虚拟机环境,还用适用于容器环境
1).VXLAN 支持更多子网(VLAN支持吃2的12次方子网即为4096个子网,Vxlan支持2的24方个子网),并通过VNI(Virtual Network identifier)区分不同 的子网,相当于VLAN中的LAN ID
2).多租户网络隔离,不同用户之间需要独立地分配IP和MAC地址
3).云计算业务对业务灵活性要求很高,虚拟机可能会大规模迁移,并保证网络一直可用。解决这个问题同时保证二层的广播域不会过分扩大,这也是云计算网络的要求
2.1 VXLAN 组网模式
Network Overlay 隧道封装在物理交换机完成。这种Overlay的优势在于物理网络设备性能转发性能比较高,可以支持非虚拟化的物理服务器之间的组网互通。
Host Overlay 隧道封装在vSwitch、具备VXLAN功能的软件完成,不用增加新的网络设备即可完成Overlay部署,可以支持虚拟化的服务器之间的组网互通。
Hybrid Overlay是Network Overlay和Host Overlay的混合组网,可以支持物理服务器和虚拟服务器之间的组网互通。
2.2 VXLAN 架构图
2.3 VXLAN 数据流向
1) 源容器veth0向目标容器发送数据,根据容器内的默认路由,数据首先发送给宿主机的docker0网桥
2)宿主机docker0网桥接受到数据后,宿主机查询路由表,pod相关的路由都是交由flannel.1网卡,因此,将其转发给flannel.1虚拟网卡处理
3)flannel.1接受到数据后,查询etcd数据库,获取目标pod网段对应的目标宿主机地址、目标宿主机的flannel网卡的mac地址、vxlan vnid等信息。然后对数据进行udp封装如下:
udp头封装:
source port >1024,target port 8427
udp内部封装:
vxlan封装:vxlan vnid等信息
original layer 2 frame封装:source {源 flannel.1网卡mac地址} target{目标flannel.1网卡的mac地址}
完成以上udp封装后,将数据转发给物理机的eth0网卡
4)宿主机eth0接收到来自flannel.1的udp包,还需要将其封装成正常的通信用的数据包,为它加上通用的ip头、二层头,这项工作在由linux内核来完成。
Ethernet Header的信息:
source:{源宿主机机网卡的MAC地址}
target:{目标宿主机网卡的MAC地址}
IP Header的信息:
source:{源宿主机网卡的IP地址}
target:{目标宿主机网卡的IP地址}
通过此次封装,一个真正可用的数据包就封装完成,可以通过物理网络传输了。
5)目标宿主机的eth0接收到数据后,对数据包进行拆封,拆到udp层后,将其转发给8427端口的flannel进程
6)目标宿主机端flannel拆除udp头、vxlan头,获取到内部的原始数据帧,在原始数据帧内部,解析出源容器ip、目标容器ip,重新封装成通用的数据包,查询路由表,转发给docker0网桥;
7)最后,docker0网桥将数据送达目标容器内的veth0网卡,完成容器之间的数据通信
3 Host-GW方式
flannel的udp模式和vxlan模式都是属于隧道方式,也就是在udp的基础之上,构建虚拟网络,host-gw模式是个例外,host-gw模式属于路由的方式,由于没有经过任何封装,纯路由实现,数据只经过协议栈一次,因此性能比较高;
host-gw模式通过建立主机IP到主机上对应flannel子网的mapping,以直接路由的方式联通flannel的各个子网。这种互联方式没有vxlan等封装方式带来的负担,通过路由机制,实现flannel网络数据包在主机之间的转发。但是这种方式也有不足,那就是所有节点之间都要相互有点对点的路由覆盖,并且所有加入flannel网络的主机需要在同一个LAN里面;所以每个节点上有n-1个路由,而n个节点一共有n(n-1)/2个路由以保证flannel的flat网络能力
host-gw的工作原理,其实就是在宿主机上,添加一条到达每个fannel子网的路由,这条路由的下一跳即网关就是相对应的fannel子网所在的“主机”。这些路由规则是flanneld根据容器部署的场景创建和更新的
3.1 Host-GW 架构图
3.2 Host-GW 数据流向
1)源容器veth0向目标容器发送数据,根据容器内的默认路由,数据首先发送给宿主机的docker0网桥,并进入内核协议栈
2)经过netfilter的PREROUTING,再进入到路由子系统,此时由于宿主机没有任何额外的设备,**匹配到默认路由**,从宿主机的eth0发出,数据包直接发送至目的节点所在的宿主机
3) 数据帧通过宿主机的二层网络顺利到达节点目的节点
二. Flannel 安装部署:
1 部署环境
2 安装部署
#tar -xf flannel-v0.13.0.tar.gz
#mv /apps/svr/flannel-v0.13.0
#ln –svfn /apps/svr/flannel-v0.13.0 /apps/svr/flannel
2.1 调整Flannel配置文件
#cd /apps/conf/flannel
#cat flannel.cfg
# Flanneld configuration options
# etcd url location. Point this to the server where etcd runs
ETCD_ENDPOINTS="http://10.65.6.3:2379,http://10.65.6.4:2379,http://10.65.6.5:2379"
# etcd config key. This is the configuration key that flannel queries
# For address range assignment
ETCD_PREFIX="/flannel/network"
# Any additional options that you want to pass
FLANNEL_OPTIONS="-iface=bond0"
2.2 启动命令
#cd /usr/libs/systemd/system
#cat flannel.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
#Before=docker.service
[Service]
Type=notify
EnvironmentFile=/apps/conf/flannel/flannel.cfg
ExecStart=/apps/svr/flannel/bin/flanneld \
-etcd-endpoints=${ETCD_ENDPOINTS} \
-etcd-prefix=${ETCD_PREFIX} \
$FLANNEL_OPTIONS
ExecStartPost=/apps/svr/flannel/bin/mk-docker-opts.sh -d /run/flannel/subnet.env
Restart=on-failure
LimitNOFILE=1000000
LimitNPROC=1000000
LimitCORE=1000000
[Install]
WantedBy=multi-user.target
2.3 调整docker启动配置,增加flannel subnet.env环境变量,并重启docker进程
#vim /usr/libs/system/system/docker.service
[Service]
Type=notify
EnvironmentFile=-/run/flannel/subnet.env
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd $DOCKER_OPTS -H fd:// --containerd=/run/containerd/containerd.sock
#systemctl daemon-reload
#systemctl restart docker
2.4 通过etcd设置flannel管理的网段及flannel工作模式
#设置vxlan
/apps/svr/etcd/sbin/etcdctl \
--endpoints="http://10.65.6.3:2379,http://10.65.6.4:2379,http://10.65.6.5:2379" set /flannel/network/config '{"Network":"10.80.0.0/16", "SubnetLen": 24, "Backend": {"Type": "vxlan"}}'
#设置vxlan Directrouting
/apps/svr/etcd/sbin/etcdctl \
--endpoints="http://10.65.6.3:2379,http://10.65.6.4:2379,http://10.65.6.5:2379" set /flannel/network/config '{"Network":"10.80.0.0/16", "SubnetLen": 24, "Backend": {"Type": "vxlan","Directrouting": true }}'
#设置HOST-GW 模式
/apps/svr/etcd/sbin/etcdctl \
--endpoints="http://10.65.6.3:2379,http://10.65.6.4:2379,http://10.65.6.5:2379" set /flannel/network/config '{"Network":"10.80.0.0/16", "SubnetLen": 24, "Backend": {"Type": "host-gw" }}'
#设置UDP模式
/apps/svr/etcd/sbin/etcdctl \
--endpoints="http://10.65.6.3:2379,http://10.65.6.4:2379,http://10.65.6.5:2379" set /flannel/network/config '{"Network":"10.80.0.0/16", "SubnetLen": 24, "Backend": {"Type": "udp" }}'
2.5 查看flannel.1网卡及路由信息
# ifconfig flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.80.58.0 netmask 255.255.255.255 broadcast 10.80.58.0
inet6 fe80::74f9:1bff:fe63:37 prefixlen 64 scopeid 0x20<link>
ether 76:f9:1b:63:00:37 txqueuelen 0 (Ethernet)
RX packets 161301 bytes 34062775 (32.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 88102 bytes 53006628 (50.5 MiB)
TX errors 0 dropped 5 overruns 0 carrier 0 collisions 0
到mtu为1450(IP头、UDP头、MAC头、vxlan协议共占了50)
# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.80.58.1 netmask 255.255.255.0 broadcast 10.80.58.255
inet6 fe80::42:e0ff:fe58:276b prefixlen 64 scopeid 0x20<link>
ether 02:42:e0:58:27:6b txqueuelen 0 (Ethernet)
RX packets 51631431 bytes 5646040919 (5.2 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 55496509 bytes 14532143853 (13.5 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2.6 查看路由
# ip route show
default via 10.65.4.254 dev bond0.100
10.65.4.0/24 dev bond0.100 proto kernel scope link src 10.65.4.1
10.80.20.0/24 via 10.80.20.0 dev flannel.1 onlink
10.80.27.0/24 via 10.80.27.0 dev flannel.1 onlink
10.80.58.0/24 dev docker0 proto kernel scope link src 10.80.58.1
169.254.0.0/16 dev bond0 scope link metric 1006
169.254.0.0/16 dev bond0.100 scope link metric 1007