容器跨主通信Flannel
在已有宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络,这种技术被称为:Overlay Network(覆盖网络)
Flannel UDP
准备
- 宿主机Node1上有一个容器container-1,IP地址:100.96.1.2,对应docker0网桥地址:100.96.1.1/24
- 宿主机Node2上有一个容器container-2,IP地址:100.96.2.3,对应docker0网桥地址:100.96.2.1/24
过程
- container-1容器里的进程发起IP包,源地址是100.96.1.2,目的地址就是100.96.2.3。由于不在Node1的docker0网桥的网段,所以这个IP包会被交给默认路由规则,从而出现在宿主机上
- 这个IP包的下一个目的地,取决于宿主机上的路由规则。Flannel已经在宿主机上创建出了一系列路由规则,会进入flannel0的设备中
- 100.96.0.0/16 dev flannel0 proto kernel scope link src 100.96.2.0 flannel设备
- 100.96.1.0/24 dev docker0 proto kernel scope link src 100.96.2.1 本机flannel分配的网段
- flannel0设备是一个TUN设备,工作在三层的虚拟设备:在操作系统内核和用户应用程序之间传递IP包
- 当操作系统将一个IP包发送给flannel0设备之后,flannel0就会把这个IP包交给Flannel进程,这是从内核态向用户态的流动;反之Flannel进程向flannel0设备发送一个IP包,那么这个IP包就会出现在宿主机网络栈中,然后根据宿主机的路由表进行下一步处理,这是用户态向内核态的流动
- 所以,当 IP 包从容器经过 docker0 出现在宿主机,然后又根据路由表进入 flannel0 设备后,宿主机上的 flanneld 进程(Flannel 项目在每个宿主机上的主进程),就会收到这个 IP 包。然后,flanneld 看到了这个 IP 包的目的地址,是 100.96.2.3,就把它发送给了 Node 2 宿主机。
- flanneld收到container-1发送给container-2的IP包之后,就会把这个IP包直接封装在一个UDP包里,然后发送给Node2,UDP包的源地址就是flanneld所在Node1的地址,而目的地址,则是container-2所在宿主机Node2的地址
- 这个请求得以完成的原因是,每台宿主机上的 flanneld,都监听着一个 8285 端口,所以 flanneld 只要把 UDP 包发往 Node 2 的 8285 端口即可。
- container-2所在宿主机的flanneld从UDP包中解析出封装在里面的原IP包,发送给flannel0设备
- 通过本机的路由表来寻找IP包的流向,第三条路由规则发送给docker0网桥
- 通过docker网桥原理,docker0网桥地址范围分配为Flannel为宿主机分配的子网,通过bip参数设置
flannel 如何知道这个IP地址对应的容器,是运行在Node2上的
- flannel事先给Node节点分配子网如100.96.2.0/24 ,将子网与宿主机的对应关系保存在Etcd中。
- 所以,flanneld 进程在处理由 flannel0 传入的 IP 包时,就可以根据目的 IP 的地址(比如 100.96.2.3),匹配到对应的子网(比如 100.96.2.0/24),从 Etcd 中找到这个子网对应的宿主机的 IP 地址是 10.168.0.3
UDP模式有严重的性能问题
- 仅在发出IP包的过程中,就需要经过三次用户态和内核态之间的数据拷贝
- Flannel进行UDP封装和解封装的过程,都是用户态完成的,代价是比较高的
Flannel VXLAN
VXLAN:Virtual Extensible LAN(虚拟可扩展局域网),是Linux内核本身就支持的一种网络虚拟化技术。VXLAN可以完全在内核态实现上述封装和解封装的工作
VXLAN的覆盖网络设计思想:在现有三层网络之上,”覆盖“一层虚拟的、由内核VXLAN模块负责维护的二层网络。
VXLAN在宿主机上设置一个特殊的网络设备作为”隧道“的两端。这个设备就叫做VTEP,它和flanneld进程非常相似,只不过进行封装和解封装的对象是二层数据帧,全部在内核完成
数据包流程
-
源IP:10.1.15.2 目IP:10.1.16.3的数据包经过docker0网桥
-
路由到本机的flannel.1设备处
-
获取需要封装目的VTEP设备信息的IP和MAC
- 每台宿主机上的flanneld进程负责维护,每次新加入节点flanneld中会添加一条路由规则,有目的IP地址
- mac地址也由flanneld维护
-
Linux内核开始二层封装工作,添加Inner Ethernet Header(目的VTEP设备的MAC地址),Inner IP Header(目的容器的IP地址),单纯添加头
-
上面的VTEP设备的MAC地址对宿主机网络没有作用,需要额外封装成普通数据帧
-
封装一个VXLAN头,其中头有一个重要的标志叫做VNI,它是VTEP设备识别某个数据帧是不是归自己处理,在Flannel中,VNI默认是1
-
flannel.1设备实际扮演一个”网桥“的角色,在Linux内核里,网桥设备转发的依据是一个叫做FDB(Forwarding Database)的转发数据库。flannel.1的FDB也是flanneld维护。通过之前的VTEP的mac地址可以找到目的主机IP
-
目的主机的MAC,通过Node1 ARP表要学习的内容
-
封包完成
-
Node1上的flannel.1设备把这个数据帧从Node1的eth0网卡发出去,经过Node2的eth0网卡
-
Node2的内核网络栈发现数据帧中的VXLAN Header,并且VNI=1,内核进行拆包,交给flannel.1设备
-
而flannel.1设备进行进一步拆包,取出”原始IP包“