暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

flannel vxlan实现Docker Overlay网络

稻壳编程 2021-06-12
667

211工程院校贵州大学管理学院硕士研究生、全国百强城商行资讯科技部五级专技工程师、互联网金融行业资深DevOps研发工程师、金融科技运维自动化平台研发项目经理。曾在国内多家知名互联网公司 平安科技、微众银行、顺丰科技、魅族任职. 具有多年国内一线互联网公司自动化运维平台设计与开发经验。



 1 

vxlan介绍

Virtual extensible Local Area Network(VXLAN)是一个在已有的3层物理网络上构建虚拟大2层逻辑网络的协议。其本质上是一种隧道封装技术,采用了TCP/IP协议栈中的封装/解封装手段,将L2层以太数据帧封装成了L4层的UDP报文,然后在L3网络层中传输,效果就好像位于不同物理网段中的L2层以太帧像在一个广播域内传输一样,实际上是跨越了L3层网络,但却又感知不到L3层网络的存在。网络拓扑如下图所示:


 2 

vxlan产生背景

1. VLAN ID 数量的限制
随着云计算的广泛普及与应用,通过虚拟化技术一台性能强劲的物理服务器上能够虚拟化出多台虚拟机,这些虚拟机又分属于不同租户,出于网络安全考虑,不同租户虚拟主机需要划分至不同的vlan中以保证网络安全,那么整个云数据中心可能要划分超过成千上万个的广播域(注:一个vlan等于一个广播域等于一个逻辑子网),而传统的网络设备上VLAN 的数量最多只能划分4096个。

2. 网络规模过大导致MAC地址表耗尽

交换机以MAC地址表作为寻址依据完成数据帧转发工作,当数据帧中的目标MAC地址在设备的MAC地址表中,则将数据帧从指定的接口转发出去,若不在则对数据帧做泛洪处理。在虚拟化技术没出现之前,接入层交换机的每个端口仅连接一台物理服务器,并对应一个MAC地址,当虚拟化技术出现后,一台物理服务器虚拟出大量虚拟机,交换机的一个端口虽然还是连接一台物理服务器,但却对应了多个MAC地址,这无疑会造成交换机MAC地址表的膨胀,而交换机的MAC地址表空间是有限的,若发生溢出,就会造成交换机不断的泛洪数据帧,增加了报文处理负担。


3. 虚拟机迁移范围受网络架构限制

虚拟机启动后,可能由于宿主机资源不足问题,需要将虚拟机迁移到新的宿主机服务器上。为了保证虚拟机迁移过程中业务不中断,则需要保证虚拟机的IP地址、MAC地址等参数保持不变,传统的采用VLAN的网络架构中,虚拟机的迁移无法打破物理网络的界限,导致虚拟机的部署与迁移不灵活,通俗来讲处于vlan10中的虚拟机迁移至vlan20,虚拟机所处的网段与IP必须随之变化,这与虚拟机迁移过程中,为实现业务不中断需要保持IP与MAC地址参数不变是相违背的,如下图所示:


Flannel的vxLan模式使用UDP协议封装报文,并监听8472端口从网络中接收报文,报文格式如下图所示:



 3 

Flannel vxLAN通信流程

根据如下网络拓扑,分析数据报文是如何从一个容器发送到位于不同宿主机的另外一个容器中的:

step1. WebAppFrontend容器访问BackendService容器,SIP10.1.15.2 DIP 10.1.20.2

step2. 数据报文通过容器网卡接口eth0、经由veth设备发送至docker0

step3. docker0通过匹配主机的路由表,将数据报文发送到 flannel.0 接口

step4. flannel.0是一个VETP(VXLAN Tunnel End Point)设备,对vxlan数据包进行封装和解封装操作,此时会根据flannel.0创建时设置的参数,进行vxlan封包操作

step5. 宿主机A通过物理网卡发送报文至宿主机B

step6. 宿主机B的物理网卡eth0接收报文并解封装,报文四层为UDP协议端口为8472,则将报文转发至VTEP设备flannel.0解封装

step7. 数据报文通过docker0发送至BackendService容器中



 4 

Flannel vxlan配置

准备工作:
Server_1 172.16.70.190 etcd
Server_2 172.16.70.191 docker宿主机1
Server_3 172.16.70.192 docker宿主机2

4.1 etcd安装
step1. 下载epel源
    [root@localhost yum.repos.d]#  wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    step2. 安装etcd
      [root@localhost yum.repos.d]# rpm -ivh epel-release-latest-7.noarch.rpm
      [root@localhost yum.repos.d]# yum -y install etcd

      step3. 修改配置文件

      单节点部署只保留以下三处配置即可
      --name: 节点名
      --etcd_data_dir: 数据存储路径
      --etcd_listen_client_url: 供外部客户端使用的url
      --etcd_advertise_client_urls: 广播给外部客户端使用的地址

        [root@localhost etcd]# cat  etc/etcd/etcd.conf 
        #[Member]
        ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
        ETCD_LISTEN_CLIENT_URLS="http://172.16.70.190:2379"
        ETCD_NAME="default"
        ETCD_ADVERTISE_CLIENT_URLS="http://172.16.70.190:2379"

        step4: 启动etcd

          [root@localhost etcd]# systemctl restart etcd
          [root@localhost etcd]# systemctl stop firewalld
          [root@localhost etcd]# systemctl disable firewalld
          Removed symlink etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
          Removed symlink etc/systemd/system/basic.target.wants/firewalld.service.

          step5. 验证集群健康状态

            [root@localhost etcd]# etcdctl --endpoint http://172.16.70.190:2379 cluster-health 
            member 8e9e05c52164694d is healthy: got healthy result from http://172.16.70.190:2379
            cluster is healthy


            4.2 flannel 配置

            step1. 生成配置文件flannel-vxlan.json,在配置文件中定义了,全局Overlay网络为B类的10.2.0.0/16,每一个docker宿主机从B类地址池中获取一个C段地址,并指定了网络类型为vxlan。

              {
              "Network": "10.0.0.0/16",
              "SubnetLen": 24,
              "Backend": {
              "Type": "vxlan"
              }
              }

              step2. 向etcd写入配置

                [root@localhost ~]# etcdctl --endpoint http://172.16.70.190:2379  mkdir flannel-vxlan/network
                [root@localhost ~]# etcdctl --endpoint http://172.16.70.190:2379 set flannel-vxlan/network/config < flannel-vxlan.json
                {
                "Network": "10.0.0.0/16",
                "SubnetLen": 24,
                "Backend": {
                "Type": "vxlan"
                }
                }

                step3. 安装Flannel 

                  [root@localhost src]#  wget https://github.com/flannel-io/flannel/releases/download/v0.9.1/flannel-v0.9.1-linux-amd64.tar.gz 
                  [root@localhost src]# tar -C usr/bin/ -xvf flannel-v0.9.1-linux-amd64.tar.gz


                  step4. 启动flannel

                  注意flannel的启动顺序在docker服务之前

                    [root@localhost ~]# flanneld  -etcd-endpoints=http://172.16.70.190:2379  -etcd-prefix=/flannel-vxlan/network  --ip-masq=true  --iface=172.16.70.191  
                    [root@localhost ~]# flanneld -etcd-endpoints=http://172.16.70.190:2379 -etcd-prefix=/flannel-vxlan/network --ip-masq=true --iface=172.16.70.192


                    step5. 此时docker服务宿主机上将会出现网卡flannel.1

                    vxlan模型flannel模型监听端口UDP 8472

                      [root@localhost ~]# netstat -tuan  | grep 8472
                      udp 0 0 0.0.0.0:8472 0.0.0.0:*


                      step6. 验证子网分配

                        [root@localhost ~]#  etcdctl --endpoint http://172.16.70.190:2379  ls  flannel-vxlan/network/subnets
                        /flannel-vxlan/network/subnets/10.0.65.0-24
                        /flannel-vxlan/network/subnets/10.0.32.0-24

                        可见flannel从Etcd中分别申请了两个子网, 子网信息会记录在docker宿主机的/run/flannel/subnet.env文件中;在flannel安装包中,mk-docker-opts.sh中定义了默认的环境变量文件位置。

                          # docker1
                          [root@localhost ~]# cat run/flannel/subnet.env
                          FLANNEL_NETWORK=10.0.0.0/16
                          FLANNEL_SUBNET=10.0.65.1/24
                          FLANNEL_MTU=1450
                          FLANNEL_IPMASQ=true


                          # docker2
                          [root@localhost ~]# cat run/flannel/subnet.env
                          FLANNEL_NETWORK=10.0.0.0/16
                          FLANNEL_SUBNET=10.0.32.1/24
                          FLANNEL_MTU=1450
                          FLANNEL_IPMASQ=true


                          step7. 执行脚本mk-docker-opts.sh 生成docker启动参数

                            DOCKER_OPTS=" --bip=10.0.65.1/24 --ip-masq=false --mtu=1450"

                            step8. 修改docker启动文件添加参数

                              # docker1
                              [Service]
                              Type=notify
                              # the default is not to use systemd for cgroups because the delegate issues still
                              # exists and systemd currently does not support the cgroup feature set required
                              # for containers run by docker
                              ExecStart=/usr/bin/dockerd --bip=10.0.65.1/24 --ip-masq=false --mtu=1500 -H fd:// --containerd=/run/containerd/containerd.soc
                              k
                              ExecReload=/bin/kill -s HUP $MAINPID
                              TimeoutSec=0
                              RestartSec=2
                              Restart=always


                              # docker2
                              [Service]
                              Type=notify
                              # the default is not to use systemd for cgroups because the delegate issues still
                              # exists and systemd currently does not support the cgroup feature set required
                              # for containers run by docker
                              ExecStart=/usr/bin/dockerd --bip=10.0.32.1/24 --ip-masq=false --mtu=1500 -H fd:// --containerd=/run/containerd/containerd.so
                              ck
                              ExecReload=/bin/kill -s HUP $MAINPID
                              TimeoutSec=0
                              RestartSec=2
                              Restart=always

                              step9. 启动docker验证配置

                                [root@localhost ~]# systemctl daemon-reload
                                [root@localhost ~]# systemctl restart docker

                                Step10. 创建容器,验证连通性

                                在两台docker宿主机上分别创建容器,查看获取的IP地址并验证网络连通性。

                                综上,工作在vxlan模式下的flannel配置成功。


                                 5 

                                vxlan数据流

                                下面分析一下vxlan模式下位于不同宿主机上的容器的通信流程,以上文容器10.0.65.2通过ICMP 连接 10.0.32.2为例。

                                step1. 在容器1中查看路由表, 默认网关是10.0.65.1 连接至容器的eth0接口
                                  [root@0599f5f991ae /]# ip route 
                                  default via 10.0.65.1 dev eth0
                                  10.0.65.0/24 dev eth0 proto kernel scope link src 10.0.65.2

                                  step2. 继续查看宿主机路由表,10.0.65.X连接在docker0上,目标网段10.0.32.X在flannel.1上

                                    [root@localhost ~]# ip route 
                                    default via 172.16.70.1 dev eno16777736 proto static metric 100
                                    10.0.32.0/24 via 10.0.32.0 dev flannel.1 onlink
                                    10.0.65.0/24 dev docker0 proto kernel scope link src 10.0.65.1

                                    step3. 获取vxlan网络对应的宿主机网卡真实IP

                                    由于flannel.1是一个vtep二层设备, 所以需要根据vxlan的协议标准进行二层封装转发,而二层转发的前提是需要获取远程对应IP10.0.32.X 的节点的mac地址, 由于vxlan设备在查询的mac的时候是不会发送arp信息的, 所以这时候flanneld可以从etcd里面获取目的IP所在网段对应的vtep设备的mac地址, 示例如下:

                                      [root@localhost ~]#  etcdctl --endpoint http://172.16.70.190:2379  get /flannel-vxlan/network/subnets/10.0.32.0-24 
                                      {"PublicIP":"172.16.70.192","BackendType":"vxlan","BackendData":{"VtepMAC":"4e:75:5c:b8:d8:8e"}}

                                      可见,想要将数据包传送至10.0.32.X网段的容器,需要将外层数据包的目标IP地址封装为 172.16.70.192。


                                      step4. vxlan转发

                                      在数据包经由vxlan规范封装之后, 内核需要知道将这个vxlan包送到哪个节点去. 所以需要查询本节点上的vxlan fdb(forwarding database)以获得目的端vtep对应的IP地址, 如果未能查询到则flanneld需要向etcd查询并存储到fdb中. 这时候vxlan设备就能准确的将数据包经由UDP协议发送至对端的vxlan设备flannel.1了,查询方式如下:

                                        [root@localhost ~]# bridge fdb show dev flannel.1 
                                        4e:75:5c:b8:d8:8e dst 172.16.70.192 self permanent


                                         6 

                                        结束语

                                        如果本文可以对您的工作学习带来帮助,请扫描左侧赞赏码以资鼓励作者;文章勘误请扫描右侧二维码联系作者。


                                        文章转载自稻壳编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                        评论