flannel为每个host分配一个subnet,容器从此subnet中分配IP,这些IP可以在host间路由,容器间无需NAT和port mapping就可以跨主机通信。



每个subnet都是从一个更大的IP池中划分的,flannel会在每个主机上运行一个叫flanneld的agent,其职责就是从池子中分配subnet。为了在各个主机间共享信息,flannel用etcd(与consul类似的key-value分布式数据库)存放网络配置、已分配的subnet、host的IP等信息。



数据包如何在主机间转发是由backend实现的。flannel提供多种backend,最常用的有vxlan、host-gw。


 


一、准备flannel实验环境


etcd部署在host3上,host1与host2上运行flaneld




docker 桌面启动flink_docker


hosts3上安装配置etcd: Releases · etcd-io/etcd (github.com)


wget https://github.com/coreos/etcd/releases/download/v3.4.23/etcd-v3.4.23-linux-amd64.tar.gz
tar -xzvf etcd-v3.4.23-linux-amd64.tar.gz
cd etcd-v3.4.23-linux-amd64
cp etcd* /usr/local/bin/

该脚本从github下载etcd的可执行文件并保存到/usr/local/bin/。


启动etcd并打开2379监听端口:


ETCDCTL_API=3 etcd -name etcd1 -data-dir /var/lib/etcd --advertise-client-urls http://192.168.11.83:2379 --listen-client-urls http://192.168.11.83:2379,http://127.0.0.1:2379


  • -name:取名
  • -data-dir:定义数据路径
  • --advertise-client-urls:建议使用的客户端通信url,该值用于etcd代理或etcd成员与etcd节点通信,即服务的url
  • --listen-client-urls:监听的用于客户端通信的url,对外提供服务的地址,客户端会连接到这里和 etcd 交互,同样可以监听多个


docker 桌面启动flink_github_02


 


重新打开一个终端,etcdctl  是一个客户端连接工具:


docker 桌面启动flink_github_03


可以看到,etcd3.4.23的api版本使用3。


docker 桌面启动flink_IP_04


配置开放端口:


iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 2379 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 2380 -j ACCEPT


测试 etcd 是否可用:


docker 桌面启动flink_docker 桌面启动flink_05


 


二、安装配置flannel


2.1、flannel下载地址


https://github.com/coreos/flannel/releases


flannel/running.md at master · flannel-io/flannel · GitHub


  a、host1上执行:wget https://github.com/flannel-io/flannel/releases/download/v0.20.2/flanneld-amd64 && chmod +x flanneld-amd64


   b、cp flanneld-amd64 /usr/local/bin/flanneld


   c、host2重复上述步骤。


2.2、host3上添加flannel网络配置信息到etcd


ETCDCTL_API=3 etcdctl --endpoints http://192.168.11.83:2379 put /coreos.com/network/config '{"Network": "10.2.0.0/16", "SubnetLen": 24, "SubnetMin": "10.2.1.0","SubnetMax": "10.2.20.0", "Backend": {"Type": "vxlan"}}'


  • Network:用于指定Flannel地址池10.2.0.0/16;
  • SubnetLen:用于指定分配给单个宿主机的docker0的ip段的子网掩码的长度,即10.2.X.0/24;
  • SubnetMin:用于指定最小能够分配的ip段;
  • SudbnetMax:用于指定最大能够分配的ip段,在上面的示例中,表示每个宿主机可以分配一个24位掩码长度的子网,可以分配的子网从10.2.1.0/24到10.2.20.0/24,也就意味着在这个网段中,最多只能有20台宿主机;
  • Backend:用于指定数据包以什么方式转发,默认为udp模式,host-gw模式性能最好,但不能跨宿主机网络;
  • /coreos.com/network/config:是etcd数据项的key,value是{"Network": "10.2.0.0/16", "SubnetLen": 24, "SubnetMin": "10.2.1.0","SubnetMax": "10.2.20.0", "Backend": {"Type": "vxlan"}}。这个key后面会作为flanneld的一个启动参数。

  


执行ETCDCTL_API=3 etcdctl --endpoints http://192.168.11.83:2379 get /coreos.com/network/config 确保设置成功。


docker 桌面启动flink_docker_06


2.3、启动flannel


在host1与host2上执行命令:


flanneld -etcd-endpoints=http://192.168.11.83:2379 -iface=ens33 -etcd-prefix=/coreos.com/network &


  • -etcd-endpoints;指定etcd url;
  • -iface:指定主机间数据传输使用的interface;
  • -etcd-prefix:指定etcd存放flannel网络配置信息的key。

host1上输出如下:


docker 桌面启动flink_docker 桌面启动flink_07


① ens33 被选作与外部主机通信的 interface。


② 识别 flannel 网络池 10.2.20.0/24。


③ 分配的 subnet 为 10.2.20.0/24。


flanneld 启动后,host1 内部网络会发生一些变化:


  • 一个新的 interface flannel.1 被创建,而且配置上 subnet 的第一个 IP 10.2.20.0。     
  • docker 桌面启动flink_IP_08


  • host1 添加了一条路由:目的地址为 flannel 网络 10.2.0.0/16 的数据包都由 flannel.1 转发。    
  • docker 桌面启动flink_docker_09


host2 输出类似,主要区别是 host2 的 subnet 为 10.2.12.0/24:


docker 桌面启动flink_github_10




当前网络环境拓扑图:


docker 桌面启动flink_docker 桌面启动flink_11


 


三、在Docker中使用flannel

3.1、配置Docker连接flannel


编辑 host1 的 Docker 配置文件 /usr/lib/systemd/system/docker.service,设置 --bip 和 --mtu:


docker 桌面启动flink_flannel_12


这两个参数值必须与/run/flannel/subnet.env中FLANNEL_SUBNET和FLANNEL_MTU一致:


docker 桌面启动flink_flannel_13


重启docker daemon:


systemctl daemon-reload


systemctl restart docker.service


Docker会将10.2.20.1配置到Linux bridge docker0上,并添加10.2.20.0/24的路由(之前是172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown):


docker 桌面启动flink_IP_14


host2配置类似:--bip=10.2.12.1/24  --mtu=1450


docker 桌面启动flink_docker 桌面启动flink_15


当前网络环境拓扑图:


docker 桌面启动flink_docker_16


可见,flannel没有创建新的docker网络,而是直接使用默认的bridge网络。同一主机的容器通过docker0连接,跨主机流量通过flannel.1转发。



3.2、将容器连接到flannel网络


host1上运行容器bbox1:


docker run -itd --name bbox1 busybox


host2上运行容器bbox2:


docker run -itd --name bbox2 busybox


bbox1 和 bbox2的IP分别为10.2.20.2 和 10.2.12.2:


docker 桌面启动flink_IP_17


docker 桌面启动flink_IP_18


 


四、flannel网络连通性


测试bbox1与bbox2的连通性:




bbox1能ping通位于不通subnet的bbox2,通过traceroute分析一下bbox1到bbox2的路径:


docker 桌面启动flink_docker 桌面启动flink_19


    1、bbox1与bbox2不是一个subnet,数据包发送给默认网关10.2.20.1(docker0);


    2、根据host1的路由表,数据包会发往flannel.1。

    

docker 桌面启动flink_github_20


    3、flannel.1将数据包封装成VxLAN,通过ens33发送给host2;


   4、host2收到包解封装,发现数据包目的地址为10.2.12.2,根据路由表将数据包发送给flannel.1,并通过docker0达到bbox2。

    

docker 桌面启动flink_flannel_21


 


数据流向如图:


docker 桌面启动flink_IP_22



 


五、flannel网络隔离


flannel为每个主机分配了独立的subnet,但flannel.1将这些subnet连接起来了,相互之间可以路由。


本质上,flannel将各主机上相互独立的docker0容器网络组成了一个互通的大网络,实现了容器跨主机通信。


flannel没有提供隔离。


 


六、flannel与外网连通性


因为 flannel 网络利用的是默认的 bridge 网络,所以容器与外网的连通方式与 bridge 网络一样,即:


1. 容器通过 docker0 NAT 访问外网


2. 通过主机端口映射,外网可以访问容器


docker 桌面启动flink_flannel_23