[Kubernetes]谈谈容器跨主机网络

继上篇文章:[Kubernetes]浅谈容器网络,本身给本身挖的坑,这篇文章来谈谈容器跨主机网络.
要理解容器"跨主通讯"的原理,就要来谈谈 Flannel 这个项目.
Flannel 项目是 CoreOS 公司主推的容器网络方案.提供容器网络功能的,分别是: VXLAN , host-gw , UDP .
这三种不一样的实现,表明了三种容器跨主机网络的主流实现方法.这里主要讲 VXLAN 和 UDP 模式.
先从 UDP 模式讲起.
web

  • 假设,我有两台宿主机:
    • 宿主机 Node 1 上有一个容器 container-1 ,它的 IP 地址是 100.96.1.2 ,对应的 docker0 网桥的地址是: 100.96.1.1/24
    • 宿主机 Node 2 上有一个 container-2 , 它的 IP 地址是 100.96.2.3 ,对应的 docker0 网桥的地址是: 100.96.2.1/24
  • 咱们如今的任务,就是让 container-1 访问 container-2 .
    这种状况下, container-1 容器里的进程发起的 IP 包,其源地址就是 100.96.1.2 , 目的地址就是 100.96.2.3 .因为目的地址 100.96.2.3 并不在 Node 1 的 docker0 网桥的网段里,因此这个 IP 包会被交给默认路由规则,经过容器的网关进入 docker0 网桥,从而出如今宿主机上.
    这时候,这个 IP 包的下一个目的地,就取决于宿主机上的路由规则了.此时, Flannel 已经在宿主机上建立出一系列的路由规则,以 Node1 为例,来看一下:
    docker

    # 在 Node 1 上
    $ ip route
    default via 10.168.0.1 dev eth0
    100.96.0.0/16 dev flannel0  proto kernel  scope link  src 100.96.1.0
    100.96.1.0/24 dev docker0  proto kernel  scope link  src 100.96.1.1
    10.168.0.0/24 dev eth0  proto kernel  scope link  src 10.168.0.2

    咱们可以看到,因为 IP 包的目的地址是 100.96.2.3 ,它如今匹配不到本机 docker0 网桥对应的 100.96.1.0/24 网段,只能匹配到第二条,也就是 100.96.0.0/16 对应的这条路由规则,从而进入到一个叫做 flannel0 的设备中.这个 flannel0 设备是一个 TUN 设备( Tunnel 设备)
    在 Linux 中, TUN 设备是一种工做在三层( Network Layer )的虚拟网络设备. TUN 设备的功能很是简单,就是:在操做系统内核和用户应用程序之间传递 IP 包.
    此时, IP 包根据路由表进入 flannel0 设备后,宿主机上的 flanneld进程,就会收到这个 IP 包,而后根据目的地址将它发送给 Node2 宿主机.
    那么, flanneld 是如何知道这个 IP 地址对应的容器,是运行在 Node2 上面的呢?
    编程

    在由 Flannel 管理的容器网络中,一台宿主机上的全部容器,都属于该宿主机被分配的一个"子网",在上面举的例子中, Node1 的子网是 100.96.1.0/24 , container-1 的 IP 地址是 100.96.1.2 . Node2 的子网是 100.96.2.0/24 , container-2 的 IP 地址是 100.96.2.3
    而这些子网与宿主机的对应关系,保存在 Etcd 中.因此, flanneld 进程在处理 IP 包时,能够根据目的 IP 的地址,匹配到对应的子网,在 Etcd 中找到这个子网对应的宿主机的 IP 地址便可.
    固然,这个请求得以完成的缘由是,每台宿主机上的 flanneld ,都监听着一个 8285 端口,因此 flanneld 只要把 UDP 包发往 Node2 的 8285 端口便可.接下来就是 flanneld 会直接把这个 IP 包发送给它所管理的 TUN 设备,即 flannel0 设备.,此时 Linux 内核网络栈就会负责处理这个 IP 包,根据相关规则,把这个 IP 包转发给 docker0 网桥.接下来的流程你们就清楚了(若是忘记了,能够再回去看看:[Kubernetes]浅谈容器网络), docker0 网桥会扮演二层交换机的角色,将数据包发送给正确的端口,进而经过 Veth Pair 设备到 container-2 的 Network Namespace 中.
    以上就是大概的一个流程.
    来一张图,看看会不会理解的更好一些:
    在这里插入图片描述
    咱们可以看到, Flannel UDP 模式提供的实际上是一个三层的 Overlay 网络,即:它首先对发出端的 IP 包进行 UDP 封装,而后在接收端进行解封装拿到原始的 IP 包,进而把这个 IP 包转发给目标容器.
    可是UDP模式有严重的性能问题,相比于两台宿主机之间的直接通讯,基于 Flannel UDP 模式的容器通讯多了一个额外的步骤,即 flanneld 的处理过程.由于这个过程当中,因为使用到了 flannel0 这个 TUN 设备,因此仅仅在发出 IP 包的这个过程当中,就须要通过用户态与内核态之间的数据拷贝,具体以下所示:
    在这里插入图片描述
    可是咱们在进行系统级编程时,有一个很是重要的优化原则,就是要减小用户态到内核态的切换次数,而且把核心的处理逻辑都放在内核态进行.
    网络

    基于这个问题,我们来看看 VXLAN 模式.
    VXLAN(即 Virtual Extensible LAN 虚拟可扩展局域网),是 Linux 内核自己就支持的一种网络虚拟化技术,所以 VXLAN 彻底能够在内核态上实现上述封装和解封装的工做,从而经过与前面相似的"隧道"机制,构建出覆盖网络( Overlay Network ).
    VXLAN 的覆盖网络的设计思想是:在现有的三层网络上,“覆盖"一层虚拟的,由内核 VXLAN 模块负责维护的二级网络,使得链接在这个 VXLAN 二层网络上的"主机”(虚拟机或者容器均可以)之间,能够像在同一个局域网( LAN )里那样自由通讯,固然,实际上这些"主机"可能分布在不一样的宿主机上,甚至是分布在不一样的物理机房里.而为了可以在二层网络上打通"隧道", VXLAN 会在宿主机上设置一个特殊的网络设备做为"隧道"的两端,这个设备就叫做 VTEP(即: VXLAN Tunnel End Point 虚拟隧道端点). VTEP 设备的做用,和 flanneld 进程很是类似,只是它进行封装和解封装的对象,是二层数据帧,而且这个工做的执行流程,是在内核中完成的.来看一下示意图:
    在这里插入图片描述
    图中每台宿主机上名叫 flannel.1 的设备,就是 VXLAN 所需的 VTEP 设备,它既有 IP 地址,也有 MAC 地址.而接下来 Flannel VXLAN 模式的具体工做方式,就和实际网络中工做的方式差很少了.
    VXLAN 模式组建的覆盖网络,其实就是一个由不一样宿主机上的 VTEP 设备,也就是 flannel.1 设备组成的虚拟二层网络,对于 VTEP 设备来讲,它发出的"内部数据帧"就仿佛是一直在这个虚拟的二层网络上流动同样,而这也正是「覆盖网络」的含义.
    svg

    以上内容来自我学习<深刻剖析Kubernetes>专栏文章以后的一些看法,有偏颇之处,还望指出.
    感谢您的阅读~
    性能

    相关文章
    相关标签/搜索