共计 3343 个字符,预计需要花费 9 分钟才能阅读完成。
flannel
flannel 可以为容器提供网络服务。
其模型为全部的容器使用一个 network,然后在每个 host 上从 network 中划分一个子网 subnet。
为 host 上的容器创建网络时,从 subnet 中划分一个 ip 给容器。
其采用目前比较流行的 no server 的方式,即不存在所谓的控制节点,而是每个 host 上的 flanneld 从一个 etcd 中获取相关数据,然后声明自己的子网网段,并记录在 etcd 中。
其他的 host 对数据转发时,从 etcd 中查询到该子网所在的 host 的 ip,然后将数据发往对应 host 上的 flanneld,交由其进行转发。
根据 kubernetes 的模型,即为每个 pod 提供一个 ip。flannel 的模型正好与之契合。因此 flannel 是最简单易用的 kubernetes 集群网络方案。
flannel 与 docker 的结合
flannel 的工作原理这里不重复赘述。网上有很多资料。本文主要讲一下 flannel 是怎么与 docker 结合起来的。
flannel 服务启动
flannel 服务需要先于 docker 启动。flannel 服务启动时主要做了以下几步的工作:
- 从 etcd 中获取 network 的配置信息
- 划分 subnet,并在 etcd 中进行注册
- 将子网信息记录到
/run/flannel/subnet.env
中
[root@localhost run]# cat /run/flannel/subnet.env | |
FLANNEL_NETWORK=4.0.0.0/16 | |
FLANNEL_SUBNET=4.0.34.1/24 | |
FLANNEL_MTU=1472 | |
FLANNEL_IPMASQ=false |
- 之后将会有一个脚本将 subnet.env 转写成一个 docker 的环境变量文件
/run/flannel/docker
[root@localhost run]# cat /run/flannel/docker | |
DOCKER_OPT_BIP="--bip=4.0.34.1/24" | |
DOCKER_OPT_IPMASQ="--ip-masq=true" | |
DOCKER_OPT_MTU="--mtu=1472" | |
DOCKER_NETWORK_OPTIONS="--bip=4.0.34.1/24 --ip-masq=true --mtu=1472" |
docker 服务启动
接下来,docker daemon 启动,使用 /run/flannel/docker
中的变量,作为启动参数,启动后的进程如下
[root@localhost ~]# ps -fe|grep docker | |
root 4538 4536 0 Jul20 ? 00:08:04 /usr/bin/docker-current daemon --exec-opt native.cgroupdriver=systemd --selinux-enabled --log-driver=journald --bip=4.0.100.1/24 --ip-masq=true --mtu=1472 |
容器启动
容器之后的启动,就是由 docker daemon 负责了。因为配置了bip
,因此创建出来的容器会使用该网段的 ip,并赋给容器。即容器其实还是按照 bridge 的模式,进行创建的。
flannel 与 docker 结合原理
现在问题来了,容器之间是怎么互通的呢?这里先要说道 flanneld,他会在宿主机 host 上创建一个 flannel0 的设备。
[root@localhost ~]# ip add | |
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN | |
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 | |
inet 127.0.0.1/8 scope host lo | |
valid_lft forever preferred_lft forever | |
inet6 ::1/128 scope host | |
valid_lft forever preferred_lft forever | |
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 | |
link/ether 08:00:27:b7:7e:f3 brd ff:ff:ff:ff:ff:ff | |
inet 10.8.65.66/24 brd 10.8.65.255 scope global dynamic enp0s3 | |
valid_lft 67134sec preferred_lft 67134sec | |
inet6 fe80::a00:27ff:feb7:7ef3/64 scope link | |
valid_lft forever preferred_lft forever | |
5: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN qlen 500 | |
link/none | |
inet 4.0.100.0/16 scope global flannel0 | |
valid_lft forever preferred_lft forever | |
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP | |
link/ether 02:42:2e:5e:cd:90 brd ff:ff:ff:ff:ff:ff | |
inet 4.0.100.1/24 scope global docker0 | |
valid_lft forever preferred_lft forever | |
inet6 fe80::42:2eff:fe5e:cd90/64 scope link | |
valid_lft forever preferred_lft forever |
接下来我们在看宿主机 host 上的路由信息。
[root@localhost ~]# route -n | |
Kernel IP routing table | |
Destination Gateway Genmask Flags Metric Ref Use Iface | |
0.0.0.0 10.8.65.1 0.0.0.0 UG 100 0 0 enp0s3 | |
4.0.0.0 0.0.0.0 255.255.0.0 U 0 0 0 flannel0 | |
4.0.100.0 0.0.0.0 255.255.255.0 U 0 0 0 docker0 | |
10.8.64.10 10.8.65.1 255.255.255.255 UGH 100 0 0 enp0s3 | |
10.8.65.0 0.0.0.0 255.255.255.0 U 100 0 0 enp0s3 |
现在有三个容器分别是 A /B/C
容器 | ip |
---|---|
A | 4.0.100.3 |
B | 4.0.100.5 |
C | 4.0.32.3 |
当容器 A 发送到同一个 subnet 的容器 B 时,因为二者处于同一个子网,所以容器 A / B 位于同一个宿主机 host 上,而容器 A / B 也均桥接在 docker0 上。
[root@localhost ~]# brctl show | |
bridge name bridge id STP enabled interfaces | |
docker0 8000.02422e5ecd90 no veth2d1c803 | |
veth916067e |
借助于网桥 docker0,容器 A / B 即可实现通信。
那么位于不同宿主机的容器 A 和 C 如何通信呢?这个时候就要用到了 flannel0 这个设备了。
容器 A 想要发送给容器 C,查路由表,可以知道需要使用 flannel0 接口,因此将数据发送到 flannel0。
flanneld 进程接收到 flannel0 接收的数据,然后从 etcd 中查询出 4.0.32.0/24
的子网的宿主机 host 的 ip10.8.65.53
。
[ | ]|
{"PublicIP":"10.8.65.53"} |
然后将数据封包,发送到 10.8.65.53
的对应端口,由 10.8.65.53
的 flanneld 接收,解包,并转发到对应的容器中。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-10/147494.htm
