flannel
build flannel
flannel 没有现成的执行文件可用,必须自己 build,最可靠的方法是在 Docker 容器中 build。不过用于做 build 的 docker 镜像托管在 gcr.io,国内可能无法直接访问,已把它 mirror 到了 docker hub,构建步骤如下:
下载并重命名 image。
docker pull cloudman6/kube-cross:v1.6.2-2
docker tag cloudman6/kube-cross:v1.6.2-2 gcr.io/google_containers/kube-cross:v1.6.2-2
下载 flannel 源码。
git clone https://github.com/coreos/flannel.git
开始构建。
cd flannel;make dist/flanneld-amd64
将 flanneld 执行文件拷贝到 host1 和 host2。
scp dist/flanneld-amd64 192.168.56.104:/usr/local/bin/flanneld
scp dist/flanneld-amd64 192.168.56.105:/usr/local/bin/flanneld
将 flannel 网络的配置信息保存到 etcd
先将配置信息写到文件 flannel-config.json 中,内容为:
{
"Network": "10.2.0.0/16",
"SubnetLen": 24,
"Backend": {
"Type": "vxlan"
}
}
-
Network
定义该网络的 IP 池为10.2.0.0/16
。 -
SubnetLen
指定每个主机分配到的 subnet 大小为 24 位,即10.2.X.0/24
。 -
Backend
为 vxlan,即主机间通过vxlan
通信,后面我们还会讨论host-gw
。
将配置存入 etcd:
etcdctl --endpoints=192.168.56.101:2379 set /docker-test/network/config < flannel-config.json
/docker-test/network/config
是此 etcd 数据项的 key,其 value 为flannel-config.json
的内容。key 可以任意指定,这个 key 后面会作为 flanneld 的一个启动参数。执行etcdctl get
确保设置成功。
启动 flannel
在 host1 和 host2 上执行如下命令:
flanneld -etcd-endpoints=http://192.168.56.101:2379 -iface=enp0s8 -etcd-prefix=/docker-test/network
- -etcd-endpoints 指定 etcd url。
- -iface 指定主机间数据传输使用的 interface。
-
-etcd-prefix 指定 etcd 存放 flannel 网络配置信息的 key。
host1 上输出如下:
① enp0s8 被选作与外部主机通信的 interface。
② 识别 flannel 网络池 10.2.0.0/16。
③ 分配的 subnet 为 10.2.40.0/24。
host1 上输出如下:
① enp0s8 被选作与外部主机通信的 interface。
② 识别 flannel 网络池 10.2.0.0/16。
③ 分配的 subnet 为 10.2.40.0/24。
flanneld 启动后,host1 内部网络会发生一些变化:
-
一个新的 interface flannel.1 被创建,而且配置上 subnet 的第一个 IP 10.2.40.0。
-
host1 添加了一条路由:目的地址为 flannel 网络 10.2.0.0/16 的数据包都由 flannel.1 转发。
host2 输出类似,主要区别是 host2 的 subnet 为 10.2.17.0/24:
当前环境网络拓扑如图所示:
-
配置 Docker 连接 flannel
编辑 host1 的 Docker 配置文件/etc/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.40.1 配置到 Linux bridge docker0
上,并添加 10.2.40.0/24
的路由。
host2 配置类似:
--bip=10.2.17.1/24
--mtu=1450
当前环境网络拓扑如图所示:
将容器连接到 flannel 网络
在 host1 中运行容器 bbox1:
docker run -itd --name bbox1 busybox
在 host2 中运行容器 bbox2:
docker run -itd --name bbox2 busybox
bbox1 和 bbox2 的 IP 分别为10.2.40.2
和 10.2.17.2
。
flannel 网络连通性
测试 bbox1 和 bbxo2 的连通性:
bbox1 能够 ping 到位于不同 subnet 的 bbox2,通过 traceroute 分析一下 bbox1 到 bbox2 的路径。
- bbox1 与 bbox2 不是一个 subnet,数据包发送给默认网关 10.2.40.1(docker0)。
-
根据 host1 的路由表(下图),数据包会发给 flannel.1。
- flannel.1 将数据包封装成 VxLAN,通过 enp0s8 发送给 host2。
-
host2 收到包解封装,发现数据包目的地址为 10.2.17.2,根据路由表(下图)将数据包发送给 flannel.1,并通过 docker0 到达 bbox2。
640AN6YBQ2V.jpg
另外,flannel 是没有 DNS 服务的,容器无法通过 hostname 通信。
640.png
flannel 网络隔离
flannel 为每个主机分配了独立的 subnet,但 flannel.1 将这些 subnet 连接起来了,相互之间可以路由。本质上,flannel 将各主机上相互独立的 docker0 容器网络组成了一个互通的大网络,实现了容器跨主机通信。flannel 没有提供隔离。
flannel 与外网连通性
因为 flannel 网络利用的是默认的 bridge 网络,所以容器与外网的连通方式与 bridge 网络一样,即:
- 容器通过 docker0 NAT 访问外网
- 通过主机端口映射,外网可以访问容器
flannel host-gw
与 vxlan 不同,host-gw 不会封装数据包,而是在主机的路由表中创建到其他主机 subnet 的路由条目,从而实现容器跨主机通信。要使用 host-gw 首先修改 flannel 的配置 flannel-config.json:
{
"Network": "10.2.0.0/16",
"SubnetLen": 24,
"Backend": {
"Type": "host-gw"
}
}
Type
用host-gw
替换原先的 vxlan。更新 etcd 数据库:
etcdctl --endpoints=192.168.56.101:2379 set /docker-test/network/config < flannel-config.json
Ctrl+C 掉之前 host1 和 host2 的 flanneld 进程并重启。
flanneld -etcd-endpoints=http://192.168.56.101:2379 -iface=enp0s8 -etcd-prefix=/docker-test/network
host1 上 flanneld 启动输出如下:
与之前 vxlan backend 启动时有几点不同:
① flanneld 检查到原先已分配的 subnet 10.2.40.0/24,重用之。
② flanneld 从 etcd 数据库中检索到 host2 的 subnet 10.2.17.0/24,但因为其 type=vxlan,立即忽略。
③ 两分钟后,再次发现 subnet 10.2.17.0/24,将其加到路由表中。这次没有忽略 subnet 的原因是此时我们在 host2 上重启了 flanneld,根据当前 etcd 的配置使用 host-gw backend。
查看 host1 的路由表,增加了一条到 10.2.17.0/24 的路由,网关为 host2 的 IP 192.168.56.105。
类似的,host2 启动 flanneld 时会重用 subnet 10.2.17.0/24,并将 host1 的 subnet 10.2.40.0/24 添加到路由表中,网关为 host1 IP 192.168.56.104。
从 /run/flannel/subnet.env 可以看到 host-gw 使用的 MTU 为 1500:
这与 vxlan MTU=1450 不同,所以应该修改 docker 启动参数 --mtu=1500并重启 docker daemon。
下面对 host-gw 和 vxlan 这两种 backend 做个简单比较。
- host-gw 把每个主机都配置成网关,主机知道其他主机的 subnet 和转发地址。vxlan 则在主机间建立隧道,不同主机的容器都在一个大的网段内(比如 10.2.0.0/16)。
- 虽然 vxlan 与 host-gw 使用不同的机制建立主机之间连接,但对于容器则无需任何改变,bbox1 仍然可以与 bbox2 通信。
- 由于 vxlan 需要对数据进行额外打包和拆包,性能会稍逊于 host-gw。