天天看点

Flannel网络方案

     这里讲一下Flannel网络方案,梳理下其工作方式,各个环节配置,以及转发包流程。

    Fannel项目是CoreOS公司主推的容器网络方案。目前实现的技术有三种,分别是:

  • UDP
  • Vxlan
  • Host-GW

1. UDP方式

        Udp方式是Flannel项目最早支持的,也是性能最差的一种。目前已经被弃用,不过,这种方式最直接、也是最容易理解的跨主机实现。

Flannel网络方案

                                              Figure -- 1

如图Figure -- 1,有两台宿主机节点1和节点2,分别有下面的配置:

  • 节点1:有容器1,IP地址是100.96.1.2,对应的docker0网桥IP地址是100.96.1.1,网络插件后台fanneld在udp端口8285上侦听,并创建了tun设备fannel0。
  • 节点2:有容器3,IP地址是100.96.2.3,对应的docker0网桥IP地址是100.96.2.1,网络插件后台fanneld在udp端口8285上侦听,并创建了tun设备fannel0。

        这里,先讲述下flannel0这个TUN设备是个什么样的设备?在linux中,TUN设备是一种工作在三层的虚拟网络设备。它的工作原理非常简单,即:在操作系统内核和用户空间程序传递IP包。fannel0这个设备的IP地址是100.96.1.0/16,其网络地址是100.96.0.0,子网掩码:255.255.0.0,主机地址是:100.96.1.0。

      现在,来分析下节点1的容器1是如何与节点2的容器3之间互相IP通信的。

      1)容器1查询路由表,匹配缺省路由,发送到容器2目的IP是100.96.2.3包到docker0(缺省网关100.96.1.1)。

      2)节点1的交换设备docker0发现收到的报文目的mac是自己时,就不做二层转发,把报文送到ip协议栈,由内核路由转发。

               # 在节点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

             路由匹配到第二条,就是100.96.0.0/16对应的路由规则,从而进入到fannel0这个设备。

     3)在用户态的flanneld进程,会在fannel0设备上接收到这个IP包。fanneld进程查看报文的目的IP地址是100.96.2.3,通过查询etcd选择发送报文到哪个节点。

          $ etcdctl ls /coreos.com/network/subnets

             /coreos.com/network/subnets/100.96.1.0-24

             /coreos.com/network/subnets/100.96.2.0-24

            /coreos.com/network/subnets/100.96.3.0-24

         $ etcdctl get /coreos.com/network/subnets/100.96.2.0-24

           {"PublicIP":"10.168.0.3"}

      查询后,发现目的IP是100.96.2.3的容器在节点2上,fanneld把IP包封装在UDP发送给节点2。

   4)节点2的处理流程与节点1类似,最终这个IP包会送到目的容器3。

   这里需要掌握下面几个关键的知识点:

  • 发到跨宿主机容器的IP包,是根据fanneld添加的路由规则,经过fannel0这个TUN设备送到flanneld这个服务程序的。
  • TUN这种虚拟的网络设备,用在内核和用户空间互相收发IP包。
  • Etcd会记录宿主机容器网络和宿主机网络的对应关系,fanneld进程根据这些记录选择发送目的容器的报文到哪个宿主机。

思考:

      flannel0这个设备的IP地址是100.96.1.0/16,可以设置成100.96.0.1吗?为什么不能设置成100.96.1.0/24?

2. VXLAN方式

       VXLAN,即Virtual Extensible LAN(虚拟可扩展局域网),类似于VLAN(Virtual LAN),用于在物理的网络内建立逻辑上独立的二层广播域。这里讲述下它们之间的差异:

  • VLAN支持2^12=4096个标识,VXLAN支持2^24多大16M的标识。
  • VXLAN将VXLAN报文加上以太帧头后封装在UDP中,使用物理网络的ip和mac作为outer-header,通过IP网络转发;VLAN将VLAN报文加上以太帧头直接通过物理以太网转发。
  • VXlAN是在IP网络上构建的虚拟Overlay Network,这个IP网络可以跨主机、跨机房,跨地域,前提是IP互通;VLAN是在物理链路可访问的广播域局域网上建立的,地域上是有局限的。
  • VXLAN控制层面隧道实现主要分三种:软件自学习、通过控制协议学习(IS-IS或者BGP)和通过SDN controller实现。VLAN控制层面实现主要分二种:管理员静态配置(基于端口或者mac地址)和通过协议(GVRP、GARP)学习。

   VXLAN根据不同的业务场景,分为三种不同的组网模式:

  • Network Overlay 隧道封装在物理交换机完成。这种Overlay的优势在于物理网络设备性能转发性能比较高,可以支持非虚拟化的物理服务器之间的组网互通。
  • Host Overlay 隧道封装在vSwitch、具备VXLAN功能的软件完成,不用增加新的网络设备即可完成Overlay部署,可以支持虚拟化的服务器之间的组网互通。
  • Hybrid Overlay是Network Overlay和Host Overlay的混合组网,可以支持物理服务器和虚拟服务器之间的组网互通。

       在学习了VXLAN基本原理以及组网模型后,再来理解在docker容器场景,通过VXLAN技术构建一个容器间可以互相访问的Overlay Network就比较容易了。Linux内核本身就支持VXLAN,所以说,通过内核实现Host Overlay方式组网,容器场景不需要满足多租户隔离,宿主机软件学习的方式实现控制层“隧道”,仅需构建一个bridge domain的VXLAN,容器就可以通过这个虚拟的Overlay Network互相访问了。

        这里讲述下VTEP这个设备。为了能够打通“隧道”,VXLAN会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备就叫作VTEP(VXLAN Tunnel End Point)。它的作用,就是封装和解封装容器发送和接收的二层数据帧(Ethernet Frame)。

Flannel网络方案

                                           Figure -- 2

       如图Figure -- 2所示,来分析下节点1的容器1是如何与节点2的容器3是如何IP访问。为了方便叙述,接下来会把这个容器发送的IP包称为“原始IP包”,节点1和节点2上的fannel设备分别称为“源VETP设备”和“目的VETP设备”。

     1)容器1查询路由表,匹配缺省路由,发送到容器2目的IP是10.1.16.3包到docker0(缺省网关10.1.15.1)。

     2)节点1的交换设备docker0发现收到的报文目的mac是自己时,就不做二层转发,把报文送到ip协议栈,由内核路由转发到fannel.1设备处理。

      # 在节点1 上

       $ route -n

          Kernel IP routing table

          Destination     Gateway         Genmask      Flags Metric Ref  Use  Iface

          ...

         10.1.16.0       10.1.16.0       255.255.255.0   UG    0   0    0   flannel.1

         这条路由规则的意思是:发往10.1.16.0/24网段的IP包,都需要经过fannel.1设备发出,并且下一跳网关地址是:10.1.16.0。这条路由是fanneld进程在节点2启动并加入到fannel网络后,在节点1(以及所以其他节点)上添加的。

     3)节点1的flannel.1,这个“源VETP设备”收到“原始IP”后,添加Inner Ethernet Header和VXLAN Header,然后发送给“目的VTEP设备”,这个Inner二层帧格式如下:

Flannel网络方案

                                 Figure -- 3

       VNI:Virtual network identify,类似于VLAN ID,用来区别不同的VXLAN网络,VNI不同的VXAN不能二层互通。fannel网络方案缺省创建VNI为1的VXLAN。

      dst mac:“目的VTEP设备”的mac地址,在步骤二路由查询到“目的VTEP设备”的IP地址是10.1.16.0,根据ARP地址解析,来获得对应IP的mac地址。

          # 在节点1上

            $ ip neigh show dev flannel.1

              10.1.16.0 lladdr 5e:f8:4f:00:e3:37 PERMANENT

              这条ARP entry,与步骤2)的路由一样,也是fanneld进程在节点2启动加入fannel网络后添加到节点1(以及其他节点)上的。

   4)Linux内核的VXLAN模块封装这个Inner ethernet frame到UDP发送。前面已经知道了“目的VTEP设备”的IP地址,不过它在哪台宿主机上呢?在前面讲VXLAN控制层面隧道实现时有讲到有“软件自学习”这种方式,在fannel网络场景下,fannel.1设备扮演一个“网桥”的角色,fanneld进程会在“网桥”的FDB(forwarding database)里添加这么一条记录:

        # 在节点1上,使用“目的 VTEP 设备”的 MAC 地址进行查询

        $ bridge fdb show flannel.1 | grep 5e:f8:4f:00:e3:37

          5e:f8:4f:00:e3:37 dev flannel.1 dst 10.168.0.3 self permanent

      发送到“目的VTEP设备”的数据,应该通过fannel.1设备,发往IP地址为10.168.0.3的主机,即节点2,UDP包要发往的目的地找到了。

   5)接下来,就在宿主机上和正常的UDP报文(如图Figure -- 4)发送一样了。

Flannel网络方案

                               Figure -- 4

    6)节点2的处理流程与节点1类似,最终这个IP包会送到目的容器3。

思考:

  • flannel.1设备的IP地址是10.1.15.0/32,子网掩码是255.255.255.255,网络地址就是10.1.15.0,主机地址是0,这个fannel.1作为一个单点的局域网了,可以通过该设备发送包到网关10.1.16.0?
  • 宿主机不在同一IP网络的情况下,VXLAN方式可行吗?

3. Host-GW方式

       前面两小节,为大家讲述了docker容器flannel网络方案,运用UDP软件转发和VXLAN技术,解决了不同宿主机之间容器通信的问题。通过分析,这两种方式都存在着不小的性能损失。

  • UDP方式,“原始IP包”需要经过tun设备从内核态到flanneld用户态进程,然后通过UDP方式通过socket从用户态到内核态,最后通过主机网卡发送出去。
  • VXLAN方式,虽然linux内核本身就支持该功能,不过整个通信过程,多了额外的封装和解封装,也带来不少的性能损耗。

       除了上面两种方式外,还有一种纯三层的网络方案(pure layer3),根据测试,host-gw的性能损失在10%左右,VXLAN方式,性能损失在20%~30%左右,UDP方式就更大了。而且,学习配置好路由规则后,数据层面的转发在内核IP路由完成,不需要额外的软件参与。

Flannel网络方案

                                      Figure -- 5

      如图Figure -- 5,节点1上的容器1访问节点2上的容器3。docker0设备在收到“原始IP包”后,查询路由表,发现这么一条路由规则:

      10.1.16.0/24 via 10.168.0.3 dev eth0

这条规则的含义是:目的地址属于10.1.16.0/24网段的IP包,都应该经过本机的eth0发送出去,并且它的下一跳是10.168.0.3。从figure -- 8可以看到,这个下一跳就是目的宿主机节点2的IP地址。这样,这个数据帧就会从节点1通过宿主机的二层网络顺利到达节点2。

知识点:

        Host-gw的工作原理,其实就是在宿主机上,添加一条到达每个fannel子网的路由,这条路由的下一跳即网关就是相对应的fannel子网所在的“主机”。这些路由规则是flanneld根据容器部署的场景创建和更新的。