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。
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
重新打开一个终端,etcdctl 是一个客户端连接工具:
可以看到,etcd3.4.23的api版本使用3。
配置开放端口:
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 是否可用:
二、安装配置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 确保设置成功。
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上输出如下:
① 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:
当前网络环境拓扑图:
三、在Docker中使用flannel
3.1、配置Docker连接flannel
编辑 host1 的 Docker 配置文件 /usr/lib/systemd/system/docker.service,设置 --bip 和 --mtu:
这两个参数值必须与/run/flannel/subnet.env中FLANNEL_SUBNET和FLANNEL_MTU一致:
重启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):
host2配置类似:--bip=10.2.12.1/24 --mtu=1450
当前网络环境拓扑图:
可见,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:
四、flannel网络连通性
测试bbox1与bbox2的连通性:
bbox1能ping通位于不通subnet的bbox2,通过traceroute分析一下bbox1到bbox2的路径:
1、bbox1与bbox2不是一个subnet,数据包发送给默认网关10.2.20.1(docker0);
2、根据host1的路由表,数据包会发往flannel.1。
3、flannel.1将数据包封装成VxLAN,通过ens33发送给host2;
4、host2收到包解封装,发现数据包目的地址为10.2.12.2,根据路由表将数据包发送给flannel.1,并通过docker0达到bbox2。
数据流向如图:
五、flannel网络隔离
flannel为每个主机分配了独立的subnet,但flannel.1将这些subnet连接起来了,相互之间可以路由。
本质上,flannel将各主机上相互独立的docker0容器网络组成了一个互通的大网络,实现了容器跨主机通信。
flannel没有提供隔离。
六、flannel与外网连通性
因为 flannel 网络利用的是默认的 bridge 网络,所以容器与外网的连通方式与 bridge 网络一样,即:
1. 容器通过 docker0 NAT 访问外网
2. 通过主机端口映射,外网可以访问容器