flannel是CoreOS开发的容器网络解决方案。
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。
![](https://img-blog.csdnimg.cn/b5be250400d24100b7709b8c37180243.png)
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 交互,同样可以监听多个
![](https://img-blog.csdnimg.cn/3fb07b3ebc424f1eb63eb2468e16aea0.png)
重新打开一个终端,etcdctl 是一个客户端连接工具:
![](https://img-blog.csdnimg.cn/4ea97d70f6ad42348727d85034277e29.png)
可以看到,etcd3.4.23的api版本使用3。
![](https://img-blog.csdnimg.cn/a7a5e1adf11c40ac91ad4169cd0464e9.png)
配置开放端口:
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 是否可用:
![](https://img-blog.csdnimg.cn/8fe7627d5d584118a0d6c2959339f803.png)
二、安装配置flannel
2.1、flannel下载地址
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 确保设置成功。
![](https://img-blog.csdnimg.cn/fb7908a4895e463a9a78199bdb7c6502.png)
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上输出如下:
![](https://img-blog.csdnimg.cn/3c2efb7191244a948d428ced8f0b17dd.png)
① 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。
-
host1 添加了一条路由:目的地址为 flannel 网络 10.2.0.0/16 的数据包都由 flannel.1 转发。
host2 输出类似,主要区别是 host2 的 subnet 为 10.2.12.0/24:
![](https://img-blog.csdnimg.cn/07bb58fab0b049a7a16a6ffd10e6e890.png)
当前网络环境拓扑图:
![](https://img-blog.csdnimg.cn/885fe9cafcc0470fb76ad964fdea1b73.png)
三、在Docker中使用flannel
3.1、配置Docker连接flannel
编辑 host1 的 Docker 配置文件 /usr/lib/systemd/system/docker.service,设置 --bip 和 --mtu:
![](https://img-blog.csdnimg.cn/469d4f83b82840dcbf4d0382e1820c30.png)
这两个参数值必须与/run/flannel/subnet.env中FLANNEL_SUBNET和FLANNEL_MTU一致:
![](https://img-blog.csdnimg.cn/f328cf44279346c8aa289283cf4378b5.png)
重启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):
![](https://img-blog.csdnimg.cn/cfc955390c33428a9e1a7de1e5b95bd6.png)
host2配置类似:--bip=10.2.12.1/24 --mtu=1450
![](https://img-blog.csdnimg.cn/92b76a77f27b4da6bc94c7b8c3cc85fa.png)
当前网络环境拓扑图:
![](https://img-blog.csdnimg.cn/bffc02852e234f5d93217bf63e683ecc.png)
可见,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:
![](https://img-blog.csdnimg.cn/1aef37330d02440b8ce3efa633bcfafc.png)
![](https://img-blog.csdnimg.cn/b214086320af47f484f1e88a042708b4.png)
四、flannel网络连通性
测试bbox1与bbox2的连通性:
bbox1能ping通位于不通subnet的bbox2,通过traceroute分析一下bbox1到bbox2的路径:
![](https://img-blog.csdnimg.cn/c142df28083d47d48138f555e0e38b49.png)
1、bbox1与bbox2不是一个subnet,数据包发送给默认网关10.2.20.1(docker0);
2、根据host1的路由表,数据包会发往flannel.1。
![](https://img-blog.csdnimg.cn/854ec132e9654162b4f723e93e791fa6.png)
3、flannel.1将数据包封装成VxLAN,通过ens33发送给host2;
4、host2收到包解封装,发现数据包目的地址为10.2.12.2,根据路由表将数据包发送给flannel.1,并通过docker0达到bbox2。
![](https://img-blog.csdnimg.cn/8f011f645dd04aaba66b0e9496080a5f.png)
数据流向如图:
![](https://img-blog.csdnimg.cn/5d8991089edb4253bc36243aefd3e8b4.png)
五、flannel网络隔离
flannel为每个主机分配了独立的subnet,但flannel.1将这些subnet连接起来了,相互之间可以路由。
本质上,flannel将各主机上相互独立的docker0容器网络组成了一个互通的大网络,实现了容器跨主机通信。
flannel没有提供隔离。
六、flannel与外网连通性
因为 flannel 网络利用的是默认的 bridge 网络,所以容器与外网的连通方式与 bridge 网络一样,即:
1. 容器通过 docker0 NAT 访问外网
2. 通过主机端口映射,外网可以访问容器
![](https://img-blog.csdnimg.cn/fcb5e44a299b4c0d9808f299ac3c62e1.png)