微服务自动化管理【Docker跨主机集群之Flannel】

  1. 环境说明
    CentOS7
    etcd-v3.4.3-linux-amd64.tar.gz
    flannel-v0.11.0-linux-amd64.tar.gz

    官方文档:https://github.com/coreos/flannel
    下载地址:https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz

1. Docker跨主机容器间网络配置
方式方式有:Pipework、Flannel、Weave、Open vSwitch(虚拟交换机)、Calico, 其中
Pipework、Weave、Flannel是使用的最多。

本文介绍的是Flannel

2. Flannel是什么
1.Flannel是CoreOS提供用于解决Dokcer集群跨主机通讯的覆盖网络工具。它的主要思路是:预先留出一个网段,
每个主机使用其中一部分,然后每个容器被分配不同的ip;让所有的容器认为大家在同一个直连的网络,
底层通过UDP/VxLAN等进行报文的封装和转发。

2.Flannel实质上是一种覆盖网络(overlay network),即表示运行在一个网上的网(应用层网络),并不依靠ip地址来传递消息,
而是采用一种映射机制,把ip地址和identifiers做映射来资源定位。也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,
目前已经支持UDP、VxLAN、AWS VPC和GCE路由等数据转发方式

 注1:Flannel支持多种Backend协议,但是不支持运行时修改Backend。官方推荐使用以下Backend:
      VXLAN,性能损耗大概在20~30%;
      host-gw, 性能损耗大概10%,要求Host之间二层直连,因此只适用于小集群;
      UDP, 建议只用于debug,因为性能烂到家了,如果网卡支持 enable udp offload,直接由网卡进行拆包解包,性能还是很棒的。
      AliVPC。

3.Flannel使用etcd存储配置数据和子网分配信息。flannel 启动之后,后台进程首先检索配置和正在使用的子网列表,
然后选择一个可用的子网,然后尝试去注册它。etcd也存储这个每个主机对应的ip。flannel使用etcd的watch机制
监视/coreos.com/network/subnets下面所有元素的变化信息,并且根据它来维护一个路由表。

 注1:etcd可以理解成springcloud中的注册中心,用于服务注册和发现,这里是节点(即宿主机)注册和发现

小结:Flannel是一种覆盖网络(overlay network),
使用etcd存储配置数据和子网分配信息
通过UDP/VxLAN等进行报文的封装和转发,建议使用VxLAN性能更好

3. 情景描述
某公司有一个简单的集群网络,在该集群内,有两台服务器甲和乙,每台服务器上都有两张网卡,分别连接公网和私网,
两台服务器可以通过私网互联,在两个服务器节点上分别安装了Docker,并且运行了A/B/C/D 4个容器。
每台服务器节点上都有一个docker0网桥,这是docker启动后初始化的虚拟设备,每个容器都与docker0网桥连接,
并且,容器的IP由docker自动分配

问题分析
1.images/01 跨主机容器互联-A.png

 默认情况下此网络设置不支持跨主机的容器互联,原因有两方面:
 1.跨主机访问容器,没有有效路由
 2.多个节点上的容器网段冲突,docker启动后初始化docker0网桥时,会随机分配一个IP段,那么,如果不加以协调,
   多个节点内的容器网络有可能会冲突,容器C和D的IP都是“192.168.1.3”

2.images/01 跨主机容器互联-B.png

4. Flannel实现的容器的跨主机通信通过如下过程实现
1.每个主机上安装并运行etcd和flannel;
2.在etcd中规划配置所有主机的docker0子网范围
3.每个主机上的flanneld根据etcd中的配置,为本主机的docker0分配子网,保证所有主机上的docker0网段不重复,
并将结果(即本主机上的docker0子网信息和本主机IP的对应关系)存入etcd库中,这样etcd库中就保存了所有主机
上的docker子网信息和本主机IP的对应关系;
4.当需要与其他主机上的容器进行通信时,查找etcd数据库,找到目的容器的子网所对应的outip(目的宿主机的IP);
5.将原始数据包封装在VXLAN或UDP数据包中,IP层以outip为目的IP进行封装;
6.由于目的IP是宿主机IP,因此路由是可达的;
7.VXLAN或UDP数据包到达目的宿主机解封装,解出原始数据包,最终到达目的容器。

注1:flannel默认使用8285端口作为UDP封装报文的端口,VxLan使用8472端口

5. Flannel的工作原理
images/02 Flannel工作原理.png

1.数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡,
这是个P2P的虚拟网卡,flanneld服务监听在网卡的另外一端

2.Flannel通过Etcd服务(重点)维护了一张节点间的路由表,该张表里保存了各个节点主机的子网网段信息
flannel默认使用etcd作为配置和协调中心,首先使用etcd设置集群的整体网络。

3.源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务,
数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,然后被转发到目的主机的docker0虚拟网卡,
最后就像本机容器通信一样的由docker0路由到达目标容器

这样整个数据包的传递就完成了,这里需要解释三个问题:
1)UDP封装是怎么回事
在UDP的数据内容部分其实是另一个ICMP(也就是ping命令)的数据包。原始数据是在起始节点的Flannel服务上进行UDP封装的,
投递到目的节点后就被另一端的Flannel服务还原成了原始的数据包,两边的Docker服务都感觉不到这个过程的存在
2)为什么每个节点上的Docker会使用不同的IP地址段
这个事情看起来很诡异,但真相十分简单。其实只是单纯的因为Flannel通过Etcd分配了每个节点可用的IP地址段后,
偷偷的修改了Docker的启动参数。在运行了Flannel服务的节点上可以查看到Docker服务进程运行参数(ps aux|grep docker|grep “bip”),
例如“–bip=182.48.25.1/24”这个参数,它限制了所在节点容器获得的IP范围。这个IP范围是由Flannel自动分配的,
由Flannel通过保存在Etcd服务中的记录确保它们不会重复。
3)为什么在发送节点上的数据会从docker0路由到flannel0虚拟网卡,在目的节点会从flannel0路由到docker0虚拟网卡
例如现在有一个数据包要从IP为10.1.15.2的容器发到IP为10.1.20.3的容器。根据数据发送节点的路由表,
它只与10.1.0.0/16匹配这条记录匹配,因此数据从docker0出来以后就被投递到了flannel0。
同理在目标节点,由于投递的地址是一个容器,因此目的地址一定会落在docker0对于的10.1.20.1/24这个记录上,
自然的被投递到了docker0网卡。

6. Flannel安装配置
0.机器环境(CentOS7)
一共三台机器:一个etcd集群,三台机器安装flannel和Docker
节点名称 IP地址(根据自己机器变化) 软件环境
node-1 192.168.238.130 etcd、flannel、docker
node-2 192.168.238.131 etcd、flannel、docker
node-3 192.168.238.132 etcd、flannel、docker

 注1:通常按照需求将集群节点部署为3,5,7,9个节点。这里能选择偶数个节点吗?最好不要这样。原因有二:
      1.偶数个节点集群不可用风险更高,表现在选主过程中,有较大概率或等额选票,从而触发下一轮选举
      2.偶数个节点集群在某些网络分割的场景下无法正常工作。当网络分割发生后,将集群节点对半分割开。
        此时集群将无法工作。按照RAFT协议,此时集群写操作无法使得大多数节点同意,从而导致写失败,集群无法正常工作

###################################################

以下均为node-0机器上的操作

###################################################
1.docker安装与配置(略)
如果不了解请看:Docker入门

2.etcd集群安装与配置(略)
如果不了解请看:etcd快速集群

 注1:ETCD3.4版本中ETCDCTL_API=3和etcd --enable-v2=false成为了默认配置
      flannel操作etcd使用的是v2的API,而kubernetes操作etcd使用的v3的API
      为了兼容flannel,将默认开启v2版本,故配置文件中还要设置 
      ETCD_ENABLE_V2="true"
      经实践:ETCD_ENABLE_V2无效,flannel连接不上etcd,最后不得不修改环境变量(之后再考虑兼容性问题)
      vi /etc/profile
      export ETCDCTL_API=2 # 指定etcdctl命令的版本为v2
      刷新配置:
      source /etc/profile

 注2:etcdctl2和etcdctl3是不兼容的,两者的api参数也不一样,最最关键的是“v2/v3的数据是不互通的”

      api 2 使用方法
      ETCDCTL_API=2 etcdctl set key value
      ETCDCTL_API=2 etcdctl ls /
      ETCDCTL_API=2 etcdctl del / --prefix 
      
      api 3 使用方法                  
      ETCDCTL_API=3 etcdctl put key value
      ETCDCTL_API=3 etcdctl get / 
      ETCDCTL_API=3 etcdctl del / --prefix 

 注3:是不是要用v2的命令保存数据,flannel才能通过v2命令获得数据

3.向etcd注册网段,供flanneld使用
错误:“failed to retrieve network config: 100: Key not found (/coreos.com)”
这里有个巨大的坑:etcd-v3.4.3中,虽然开启了兼容模式,但v2/v3命令保存的数据是不互通的,
所以要使用v2的set命令而非v3的put命令保存数据,因为etcd开启了兼容模式,所以在命令前面添加
ETCDCTL_API=2,切换到v2版本的命令即可

 ##1.使用v2版的set(而非put)命令向ETCD中保存flannel覆盖网络信息
 ETCDCTL_API=2 etcdctl --endpoints "http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379" \
   set /coreos.com/network/config '{"NetWork":"10.0.0.0/16","SubnetMin": "10.0.1.0", "SubnetMax": "10.0.20.0","Backend": {"Type": "vxlan"}}' 

 ##2.v2命令获得网络信息
 ETCDCTL_API=2 etcdctl --endpoints "http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379" get /coreos.com/network/config

 注1:etcd保存的网络参数说明
      '{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}'


      10.0.0.0/16:请参考附录三
      Network: 用于指定Flannel地址池, 整个overlay(覆盖)网络为10.0.0.0/16网段.
      SubnetLen: 用于指定分配给单个宿主机的docker0的ip段的子网掩码的长度,默认值也是24
      SubnetMin: 用于指定最小能够分配的ip段
      SudbnetMax: 用于指定最大能够分配的ip段,在上面的示例中,表示每个宿主机可以分配一个24位掩码长度的子网,
        可以分配的子网从10.0.1.0/24到10.0.20.0/24,也就意味着在这个网段中,最多只能有20台宿主机


      Backend: 用于指定数据包以什么方式转发,默认为udp模式, 这里使用的是vxlan模式.因为为vxlan比起预设的udp性能相对好一些  

 注2:如何知道v2/v3命令保存的数据是不兼容的呢
      ## v3命令查询,无数据
      etcdctl --endpoints "http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379" get /coreos.com/network/config
      ## v2命令查询,有数据
      ETCDCTL_API=2 etcdctl --endpoints "http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379" get /coreos.com/network/config
                
 注3:flannel访问etcd时使用的key默认为:/coreos.com/network,可修改,但必须重新配置flanneld.conf的参数etcd-prefix,
      例如:-etcd-prefix=/zking.com/network    

4.安装flannel
##1.下载或rz上传flannel安装包
安装包:https://pan.baidu.com/s/1o6d4WgT_2uu6B7IGInHwQQ
提取码:vuv2
cd /usr/local/mytools
rz
##2.创建flannel安装目录
mkdir -p /opt/flannel

##3.解压安装文件至指定目录
tar xzf flannel-v0.11.0-linux-amd64.tar.gz -C /opt/flannel

##4.查看解压后文件:主要有flanneld、mk-docker-opts.sh这两个文件,其中flanneld为主要的执行文件,sh脚本用于生成Docker启动参数

cd /opt/flannel && ls

5.为flannel创建一个systemd服务,用于后台启动
vim /etc/systemd/system/flanneld.service

flanneld.service:

[Unit]
Description=Flanneld
After=network.target
After=network-online.target
Wants=network-online.target
##1.flannel服务需要先于Docker启动,后于etcd启动
After=etcd.service
Before=docker.service


[Service]
User=root
##2.ExecStart即flanneld启动程序位置
##3.--etcd-endpoints参数为ectd集群客户端地址
##4.--iface参数为要绑定的网卡的IP地址,或是网卡名(ifconfig查看获得)请根据实际情况修改
ExecStart=/opt/flannel/flanneld \
--etcd-endpoints=http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379 \
--etcd-prefix=/coreos.com/network \
--iface=ens33 \
--ip-masq
Restart=on-failure
Type=notify
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
 1.启动脚本关键参数:
 ##1.flannel服务需要先于Docker启动,后于etcd启动
 After=etcd.service
 Before=docker.service
 ##2.ExecStart即flanneld启动程序位置
 ExecStart=/opt/flannel/flanneld
 ##3.--etcd-endpoints参数为ectd集群客户端地址
 --etcd-endpoints="http://192.168.199.160:2379,http://http://192.168.199.157:2379,http://http://192.168.199.158:2379" \
 ##4.--iface参数为要绑定的网卡的网卡名(或IP地址)请根据实际情况修改,注意:IP或网卡名都可用ifconfig命令获得
 --iface=ens33

2.flannel启动过程解析
  flannel服务需要先于Docker启动。flannel服务启动时主要做了以下几步的工作:
  1.从etcd中获取network的配置信息
  2.划分subnet,并在etcd中进行注册
  3.将子网信息记录到/run/flannel/subnet.env中

6.flanneld服务启用/自启/停止/重启
systemctl daemon-reload && systemctl enable flanneld && systemctl start flanneld && systemctl status flanneld
systemctl stop flanneld
systemctl restart flanneld

 调试相关命令:
 cd /var/lib/etcd && rm -rf *
 systemctl daemon-reload && systemctl restart flanneld


 如果启动失败,可通过如下命令查看原因
 ## 显示概要
 systemctl status flanneld.service
 ## 可以查看启动参数 
 ps -ef |grep flanneld
 ## 查看启动详情
 journalctl -xe
 ## 显示实时日志
 journalctl -f
 ## 查看本机监听端口
 netstat -tunlp|grep etcd

7.验证flannel网络
1.flanneld服务启动成功后,使用ifconfig命令查看系统,会发现系统多了一个虚拟网卡“flannel.1”
注:“flannel.1”为生成的虚拟网卡名,此名字不固定,以实际情况为准

 2.在etcd集群的任一节点上都可以查看到子网IP
   ETCDCTL_API=2 etcdctl --endpoints "http://127.0.0.1:2379" ls /coreos.com/network/subnets

 3.查看“flannel.1”的网络详细情况
   ifconfig flannel.1
 
   可以看到flannel.1网卡的地址和etcd中存储的地址一样,这样flannel网络配置完成

8.配置Docker
在各个节点安装好Docker,然后更改Docker的启动参数,使其能够使用flannel进行IP分配,以及网络通讯

 1.查看flannel分配的网络参数
   ##在Flannel运行之后,会生成一个环境变量文件,包含了当前主机要使用flannel通讯的相关参数
   cat /run/flannel/subnet.env
   ##控制台显示如下内容
   FLANNEL_NETWORK=10.0.0.0/16     ##10.0.1~20.1~254(0和255是特殊值不能用)
   FLANNEL_SUBNET=10.0.14.1/24     ##10.0.14(不一定是14,可以在1~20之间).1~254
   FLANNEL_MTU=1450
   FLANNEL_IPMASQ=true
 2.创建Docker运行参数
   ##使用flannel提供的脚本将subnet.env转写成Docker启动参数
   /opt/flannel/mk-docker-opts.sh -d /run/flannel/docker_opts.env -c
   ##创建好的启动参数位于/run/flannel/docker_opts.env文件中,可使用cat命令查看
   cat /run/flannel/docker_opts.env

   注1:网上很多将docker_opts.env保存到/run目录下,run目录下重启系统后docker_opts.env文件会自动消失,引发错误
        所以改到/run/flannel目录下

 4.修改Docker启动参数
   ##编辑 systemd service 配置文件
   vim /lib/systemd/system/docker.service

   ##下面是docker.service要修改的2个地方
   ##1.[Service]节中,指定启动参数所在的文件位置(这个配置是新增的) 
   EnvironmentFile=/run/flannel/docker_opts.env
   ##在原有ExecStart后面添加$DOCKER_OPTS
   ##修改前
   #ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
   ##2.修改后
   ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock $DOCKER_OPTS

 5.重新加载systemd配置,并重启Docker即可,
   systemctl daemon-reload && systemctl restart docker && systemctl status docker

 6.查看overlay(覆盖)网络
   ##查看宿主机网络情况,此时可以看到docker0的网卡ip地址已经处于flannel网卡网段之内
   ifconfig

 7.测试flannel
   三台机器(node1/node2/node3)都配置好了之后,我们在三台机器上分别开启一个docker容器,测试它们的网络是否可相互联通的  
   ##下载centos镜像,因为此镜像中其它软件及命令均有安装
   docker pull centos

   ## 依次查看3台机器的flannel.1网络IP
   1.node-0
     ##创建/启动/进入容器 
     docker run -it centos /bin/bash
     ##进入容器后,查看容器IP
     cat /etc/hosts         
     ##控制台输出如下内容
     10.0.14.2	ff43c3e20bde
     ##另外,请注意宿主机flannel.1网络的IP为
     10.0.14.0
 
   2.node2
     ##创建/启动/进入容器 
     docker run -it centos /bin/bash
     ##进入容器后,查看容器IP
     cat /etc/hosts         
     ##控制台输出如下内容
     10.0.7.2	45f1155a3e25
     ##另外,请注意宿主机flannel.1网络的IP为
     10.0.7.0
   
   3.node3
     ##创建/启动/进入容器 
     docker run -it alpine:latest /bin/sh 
     ##进入容器后,查看容器IP
     cat /etc/hosts         
     ##控制台输出如下内容
     10.0.8.2	dd061df9ad27
     ##另外,请注意宿主机flannel.1网络的IP为
     10.0.8.0

   4.从不同宿主机容器到三台宿主机
     #-c count是数量,即发三个ping 包,请注意控制台信息
     ping -c3 192.168.238.130
     ping -c3 192.168.238.131
     ping -c3 192.168.238.132          

   5.从容器到到跨宿主机容器
     ping -c3 10.0.17.2
     ping -c3 10.0.8.2
     ping -c3 10.0.8.2 

   6.node1再启动一个容器
     ##创建/启动/进入容器 
     docker run -it cet:latest /bin/sh 
     ##进入容器后,查看容器IP
     cat /etc/hosts         
     ##控制台输出如下内容
     10.0.14.3	fbdddd756a16      
     ##另外,请注意宿主机flannel.1网络的IP为
     10.0.14.0

   7.测试同一宿主机不同容器的连接
     #10.0.14.3<-->10.0.14.3互ping
     ping -c3 10.0.14.2
     ping -c3 10.0.14.3

附录一:eth0 eth0:1 eth0.1 的区别
eth0 eth0:1 和eth0.1三者的关系对应于物理网卡、子网卡、虚拟VLAN网卡

附录二:veth是什么?
Linux container 中用到一个叫做veth的东西,这是一种新的设备,专门为 container 所建。veth 从名字上来看是
Virtual ETHernet(虚拟网络设备)的缩写,它的作用很简单,就是要把从一个 network namespace 发出的数据包转发到另一个 namespace。
veth 设备是成对的,一个是 container 之中,另一个在 container 之外,即在真实机器上能看到的

附录三:ip地址后边加个/8(16,24,32)是什么意思?
是子网掩码的位数,由于255相当于二进制的8位11111111,所以也缩写成“/8”,表示网络号占了8位

A类IP地址的默认子网掩码为255.0.0.0(/8)

B类的为255.255.0.0(/16);

C类的为255.255.255.0(/24)

/30就是255.255.255.252

/32就是255.255.255.255
例如:
xx.xx.xx.0/24 ——>表示一个网段,并且24告诉了当前具体的子网掩码

举例说吧,192.168.0.0/24”就表示,这个网段的IP地址从192.168.0.1开始,到192.168.0.254结束
(192.168.0.0和192.168.0.255有特殊含义,不能用作IP地址);子网掩码是255.255.255.0

附录四: flanneld启动失败,报错的原因如下:
Failed to create SubnetManager: parse first path segment in URL cannot contain colon

ExecStart=/usr/local/bin/flanneld
-etcd-cafile=/etc/etcd/ssl/ca.pem
-etcd-certfile=/etc/etcd/ssl/server.pem
-etcd-keyfile=/etc/etcd/ssl/server-key.pem
###是不能加引号的
##错误
##-etcd-endpoints="http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379 "
##正确
-etcd-endpoints=http://192.168.238.130:2379,http://192.168.238.131:2379,http://192.168.238.132:2379
-etcd-prefix=/coreos.com/network
-iface=ens33
-ip-masq

附录五:解决flannel下容器无法跨主机互通问题
经测试,发现是防火墙的问题,关闭防火墙后问题解决。
但作为服务的防火墙是不能关闭的,如何解决呢?
这是由于linux还有底层的iptables,所以在node上分别执行
iptables -P INPUT ACCEPT && iptables -P FORWARD ACCEPT && iptables -F && iptables -L -n
问题完美解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值