不会飞的章鱼

熟能生巧,勤能补拙;念念不忘,必有回响。

Kubernetes网络原理——容器跨主机网络

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
------ 本文结束------
如果本篇文章对你有帮助,可以给作者加个鸡腿~(*^__^*),感谢鼓励与支持!