Flannel介绍
要理解容器“跨主通信”的原理,就一定要先从Flannel
这个项目开始。
Flannel 项目是 CoreOS 公司主推的容器网络方案。事实上,Flannel 项目本身只是一个框架,真正为我们提供容器网络功能的,是 Flannel 的后端实现。目前,Flannel 支持三种后端实现(种容器跨主网络的主流实现方法。),分别是:
- VXLAN
- host-gw
- UDP
UDP模式
UDP 模式,是 Flannel 项目最早支持的一种方式,却也是性能最差的一种方式。
所以,这个模式目前已经被弃用。
不过,Flannel 之所以最先选择 UDP 模式,就是因为这种模式是最直接、也是最容易理解的容器跨主网络实现。
可以看到,Flannel UDP 模式提供的其实是一个三层的 Overlay 网络,即:它首先对发出端的 IP 包进行 UDP 封装,然后在接收端进行解封装拿到原始的 IP 包,进而把这个 IP包转发给目标容器。这就好比,Flannel 在不同宿主机上的两个容器之间打通了一条“隧道”
,使得这两个容器可以直接使用 IP 地址进行通信,而无需关心容器和宿主机的分布情况。
相比于两台宿主机之间的直接通信,基于 Flannel UDP 模式的容器通信多了一个额外的步骤,即 flanneld 的处理过程。而这个过程,由于使用到了 flannel0 这个 TUN 设备,
仅在发出 IP 包的过程中,就需要经过三次用户态与内核态之间的数据拷贝,如下所示:
- 第一次:用户态的容器进程发出的 IP 包经过 docker0 网桥进入内核态;
- 第二次:IP 包根据路由表进入 TUN(flannel0)设备,从而回到用户态的 flanneld 进程;
- 第三次:flanneld 进行 UDP 封包之后重新进入内核态,将 UDP 包通过宿主机的eth0 发出去。
此外,我们还可以看到,Flannel 进行 UDP 封装(Encapsulation)和解封装
(Decapsulation)的过程,也都是在用户态完成的。在 Linux 操作系统中,上述这些上下文切换和用户态操作的代价其实是比较高的,这也正是造成 Flannel UDP 模式性能不好的主要原因。
因此,在进行系统级编程的时候,有一个非常重要的优化原则,就是要减少用户态到内核态的切换次数,并且把核心的处理逻辑都放在内核态进行。
VXLAN模式
VXLAN,即 Virtual Extensible LAN(虚拟可扩展局域网),是 Linux 内核本身就支持的一种网络虚似化技术。
VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的“隧道”机制,构建出覆盖网络(Overlay Network)。
VXLAN 的覆盖网络的设计思想
在现有的三层网络之上,“覆盖”一层虚拟的、由内核VXLAN 模块负责维护的二层网络,使得连接在这个 VXLAN 二层网络上的“主机”(虚拟机或者容器都可以)之间,可以像在同一个局域网(LAN)里那样自由通信。
而为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为
“隧道”的两端。这个设备就叫作 VTEP,即:VXLAN Tunnel End Point(虚拟隧道端点)。
而 VTEP 设备的作用,其实跟前面的 flanneld 进程非常相似。
只不过,它进行封装和解封装的对象,是二层数据帧(Ethernet frame);而且这个工作的执行流程,全部是在内核里完成的(因为 VXLAN 本身就是 Linux 内核中的一个模块)。
图中每台宿主机上名叫 flannel.1 的设备,就是 VXLAN 所需的 VTEP 设备,它既有 IP 地址,也有 MAC 地址。
现在,我们的 container-1 的 IP 地址是 10.1.15.2,要访问的 container-2 的 IP 地址是10.1.16.3。当 container-1 发出请求之后,这个目的地址是10.1.16.3 的 原始 IP包,会先出现在 docker0 网桥,然后被路由到本机 flannel.1 设备进行处理。为了能够将“原始 IP 包”封装并且发送到正确的宿主机,VXLAN 就需要找到这条“隧道”的出口,即:目的宿主机的 VTEP 设备。而这个设备的信息,正是每台宿主机上的 flanneld 进程负责维护的。
总结
Flannel UDP
和Flannel VALAN
模式其实都可以称作“隧道”机制,也是很多其他容器网络插件的基础。比如 Weave 的两种模式,以及 Docker 的 Overlay 模式。- XLAN 模式组建的覆盖网络,其实就是一个由不同宿主机上的 VTEP 设备,也就是flannel.1 设备组成的虚拟二层网络。对于 VTEP 设备来说,它发出的“内部数据帧”就仿佛是一直在这个虚拟的二层网络上流动。这也正是覆盖网络的含义。
- 如果你想要在集群中实践 Flannel 的话,可以在 Master节点上执行如下命令来替换网络插件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 第一步
MY_ZUES_CHAR
rm -rf /etc/cni/net.d/*
# 第二步
kubectl delete -f "https://cloud.weave.works/k8s/net?k8s-version=1.11"
# 第三步
在/etc/kubernetes/manifests/kube-controller-manager.yaml里,为容器启动命令添加如下两个参数:
--allocate-node-cidrs=true
--cluster-cidr=10.244.0.0/16
# 第四步,重启所有的kubelet
# 第五步
kubectl create -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cdflannel.yml