一 简介
- Flannel是一种基于overlay网络的跨主机容器网络解决方案,也就是将TCP数据包封装在另一种网络包里面进行路由转发和通信。
- Flannel是coreOS开发,专门用于docker多机互联的一个工具,让集群中的不同节点创建的容器都基有全集群唯一的虚拟ip地址
- FLannel使用go语言编写
二 Flannel实现原理
2.1 原理说明
- Flannel为每一个host分配一个subnet,容器从这个subnet中分配IP,这些IP可以在host间路由,容器间无需使用nat和端口映射即可实现跨主机通信
- 每个subnet都是从一个更大的IP地址池划分的,flannel会在每个主机上运行一个叫flanneld的agent,其职责介绍从池子中分配subnet
- Flannle使用etcd存放网络配置,已分配的subnet,host的ip地址等信息
- Flannel数据包在主机间转发是由backend实现的,目前已经支持UDP,VxLAN,host-gw,AWS VPC和GCE路由等多种backend
2.2 Flannel网络结构图
多了一层封装,进行流量劫持
2.3 数据转发流程
- 容器直接使用目标容器的ip 访问,默认通过容器内部的eth0发送出去
- 报文通过veth pair 被发送到 veth XXX
- veth XXX 是周几连接到虚拟交换机dokcer0的,报文通过虚拟bridge dokcer0发送出去
- 查找路由表,外部容器ip的报文都会转发到flannel0虚拟网卡,这是一个P2P的虚拟网卡,然后报文就被转发到监听在另一端的flanneld
- flanneld通过etcd维护了各个节点之间的路由表,把原来的报文UDP封装一层,通过配置的iface发送出去。
- 报文通过主机之间的网络找到目标主机
- 报文继续往上,到传输层,交给监听在8285端口的flanneld程序处理
- 数据被解包,然后发送给flannel0虚拟忘记。
- 查找路由表,发现对应容器的报文要交给docker0
- dokcer0找到连到自己的容器,包报文发送过去
三 安装配置
3.1 环境准备
节点名称 | IP地址 | 安装软件 |
dokcer-server1 | 192.168.132.131 | etcd ,flannel ,docker |
dokcer-server2 | 192.168.132.132 | flannel,dokcer |
删除节点的所有容器
[root@docker-server1 ~]# docker ps -aq|xargs docker rm
[root@docker-server2 ~]# docker ps -aq|xargs docker rm
3.2 安装tecd
eetcd下载地址:https://github.com/coreos/etcd/releass
下载
[root@docker-server1 ~]# wget https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz
[root@docker-server2 ~]# wget https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz
在131上安装etcd和Flannel
[root@docker-server1 ~]# tar -xf etcd-v3.3.10-linux-amd64.tar.gz
[root@docker-server1 ~]# cd etcd-v3.3.10-linux-amd64
[root@docker-server1 etcd-v3.3.10-linux-amd64]# ll
total 33992
drwxr-xr-x 11 joy joy 4096 Jul 24 2018
Documentation-rwxr-xr-x 1 joy joy 18934016 Jul 24 2018
etcd-rwxr-xr-x 1 joy joy 15809280 Jul 24 2018
etcdctl-rw-r--r-- 1 joy joy 38864 Jul 24 2018
README-etcdctl.md-rw-r--r-- 1 joy joy 7262 Jul 24 2018
README.md-rw-r--r-- 1 joy joy 7855 Jul 24 2018
READMEv2-etcdctl.md
[root@docker-server1 etcd-v3.3.10-linux-amd64]# cp etcd* /usr/bin/
启动命令:
[root@docker-server1 ~]# etcd --name etcd-131 -data-dir /var/lib/etcd --advertise-client-urls http://192.168.132.131:2379,http://127.0.0.1:2379 --listen-client-urls http://192.168.132.131:2379,http://127.0.0.1:2379
--name:etc #取名
--data-dir:定义数据路径
--advertise-client-urls:建议使用的用户客户端通信url,该值用于etcd代理和etcd成员与etcd节点通信,即服务的url
--listen-client-urls:监听的用于客户端通信的url,对外提供服务的地址,客户端会连接到这里和etcd交互,同样可以监听多个。
[root@docker-server1 ~]# ps -ef|grep etcd
root 85130 84636 2 14:12 pts/4 00:00:01 etcd -name etcd-131 -data-dir /var/lib/etcd --advertise-client-urls http://192.168.132.131:2379,http://127.0.0.1:2379 --listen-client-urls http://192.168.132.131:2379,http://127.0.0.1:2379
etcdctl是一个客户的连接工具
[root@docker-server1 ~]# etcdctl member list
8e9e05c52164694d: name=etcd-131 peerURLs=http://localhost:2380 clientURLs=http://127.0.0.1:2379,http://192.168.132.131:2379 isLeader=true
使用etcdctl连接数据库,检查etcd的连通性
[root@docker-server1 ~]# etcdctl --endpoints http://127.0.0.1:2379 member list
8e9e05c52164694d: name=etcd-131 peerURLs=http://localhost:2380 clientURLs=http://127.0.0.1:2379,http://192.168.132.131:2379 isLeader=true
查看etcdctl版本
[root@docker-server1 ~]# etcdctl --version
etcdctl version: 3.3.10
API version: 2
[root@docker-server1 ~]# etcdctl --help
更新etxdctl版本
[root@docker-server1 ~]# export ETCDCTL_API=3
[root@docker-server1 ~]# etcdctl --help
指令已经反生变化
3.3 安装Flannel
flannel下载地址:https://github.com/coreos/flannel/releases
下载
[root@docker-server1 ~]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
[root@docker-server2 ~]# wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
[root@docker-server1 ~]# tar -xf flannel-v0.11.0-linux-amd64.tar.gz
[root@docker-server1 ~]# cp flanneld /usr/bin/
[root@docker-server1 ~]# cp mk-docker-opts.sh /usr/bin/
2. 版本etcdctl使用
添加flannel网络配置信息到etcd: 是一个键值对
[root@docker-server1 ~]# etcdctl set /coreos.com/network/config '{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}'
如果不是本机可以加参数: --endpoints http://IP:2379
{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}
Network: 用于指定Flannel地址池
SubnetLen: 用于指定分配给单个宿主机的docker0的ip段的子网掩码的长度
SubnetMin: 用于指定最小能够分配的ip段
SudbnetMax: 用于指定最大能够分配的ip段,在上面的示例中,表示每个宿主机可以分配U一个24为掩码长度的子网,可以分配的子网从10.0.1.0、24到10.0.20.0/24,也就意味着在这个网段中,最多只能有20台宿主机
Backend: 用于指定数据包以什么方式转发,默认为udp模式,host-gw模式性能最好,但不能跨宿主机网络
[root@docker-server1 ~]# etcdctl get /coreos.com/network/config {"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}
上面的操作时,时etcdctl的API版本是2可以使用,当升级到3版本后会报错
[root@docker-server1 ~]# etcdctl set /coreos.com/network/config '{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}'
3版本用法
[root@docker-server1 ~]# etcdctl --endpoints http://127.0.0.1:2379 put /coreos.com/network/config '{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}'
ok
[root@docker-server1 ~]# etcdctl get /coreos.com/network/config
/coreos.com/network/config
{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "vxlan"}}
下面的操作都是使用etcdctl V2版本
3.4 启动Flannel
[root@docker-server1 ~]# /usr/bin/flanneld --etcd-endpoints="http://192.168.132.131:2379" --iface=192.168.132.131 --etcd-prefix=/coreos.com/network &
[root@docker-server1 ~]# ip addr
[root@docker-server1 ~]# ps -ef |grep flan
root 86107 84636 0 15:02 pts/4 00:00:00 /usr/bin/flanneld --etcd-endpoints=http://192.168.132.131:2379 --iface=192.168.132.131 --etcd-prefix=/coreos.com/network
可以使用flannel提供的脚本将subnet.env转写成Docker启动参数,创建好的启动参数默认生成在/run/docker_opts.env文件中:
[root@docker-server1 ~]# mk-docker-opts.sh
[root@docker-server1 ~]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.0.0.0/16
FLANNEL_SUBNET=10.0.8.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false
[root@docker-server1 ~]# cat /run/docker_opts.env
DOCKER_OPT_BIP="--bip=10.0.4.1/24"
DOCKER_OPT_IPMASQ="--ip-masq=true"
DOCKER_OPT_MTU="--mtu=1450"
DOCKER_OPTS=" --bip=10.0.4.1/24 --ip-masq=true --mtu=1450"
需要把这个文件加到docker的启动项
[root@docker-server1 ~]# vi /usr/lib/systemd/system/docker.service
EnvironmentFile=/run/docker_opts.env
ExecStart=/usr/bin/dockerd $DOCKER_OPTS -H fd:// --containerd=/run/containerd/containerd.sock
启动dokcer
[root@docker-server1 ~]# systemctl daemon-reload
[root@docker-server1 ~]# systemctl restart docker
报错
[root@docker-server1 ~]# journalctl -xe -u docker
Nov 09 15:13:52 docker-server1 dockerd[86540]: unable to configure the Docker daemon with file /etc/docker/daemon.json: the following
Nov 09 15:13:52 docker-server1 systemd[1]: docker.service: main process exited, code=exited, status=1/FAILURE
删除/etc/docker/daemon.json里的bip配置
[root@docker-server1 ~]# systemctl restart docker
To force a start use "systemctl reset-failed docker.service" followed by "systemctl start docker.service" again.
[root@docker-server1 ~]# systemctl restart docker
[root@docker-server1 ~]# ip addr
docker0的IP是10.0.4.1
[root@docker-server1 ~]# etcdctl ls /coreos.com/network/
/coreos.com/network/subnets
/coreos.com/network/config
可以看到flannel0网卡的地址和etcd存储地址一样,这样flannel网络配置完成
Flannel启动过程解析
- 从etcd中获取network的配置xinx
- 划分subnet,并在etcd中进行注册
- 将子网信息记录到/run/flannel/subent.env中
- Flannel必须先于Docker启动
3.5 验证Flannel网络
查看etcd中的数据:
[root@docker-server1 ~]# etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/10.0.4.0-24
3.6 配置docker
Dokcer安装完成以后,需要修改其启动参数以使其能够使用flannel进行IP分配,以及网络通讯
在Flannel运行之后,会生成一个环境变量文件,包含了当前主机要使用flannel通讯的相关参数,如下:
[root@docker-server1 ~]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.0.0.0/16
FLANNEL_SUBNET=10.0.4.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false
dokcer-server相同操作配置flannel.不用安装etcd
[root@docker-server2 ~]# tar -xf flannel-v0.11.0-linux-amd64.tar.gz
[root@docker-server2 ~]# mv flanneld /usr/bin/
[root@docker-server2 ~]# mv mk-docker-opts.sh /usr/bin/
[root@docker-server2 ~]# /usr/bin/flanneld --etcd-endpoints="http://192.168.132.131:2379" --iface=192.168.132.132 --etcd-prefix=/coreos.com/network &
[root@docker-server2 ~]# mk-docker-opts.sh -c
[root@docker-server2 ~]# cat /run/docker_opts.env
修改dokcer启动文件,删除daemon.json的bip配置
[root@docker-server2 ~]# systemctl daemon-reload
[root@docker-server2 ~]# systemctl restart docker
[root@docker-server2 ~]# ip addr
[root@docker-server1 ~]# etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/10.0.8.0-24
/coreos.com/network/subnets/10.0.18.0-24
两台主机的subnet网段
[root@docker-server1 ~]# etcdctl get /coreos.com/network/subnets/10.0.18.0-24
{"PublicIP":"192.168.132.132","BackendType":"vxlan","BackendData":{"VtepMAC":"62:b9:76:44:bf:32"}}
[root@docker-server1 ~]# etcdctl get /coreos.com/network/subnets/10.0.8.0-24
{"PublicIP":"192.168.132.131","BackendType":"vxlan","BackendData":{"VtepMAC":"62:93:c1:0f:b9:b0"}}
3.7 验证容器互通
[root@docker-server1 ~]# docker run -it busybox
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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
124: eth0@if125: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:00:04:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.4.2/24 brd 10.0.4.255 scope global eth0
valid_lft forever preferred_lft forever
[root@docker-server2 ~]# docker run -it busybox
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
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
15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:00:12:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.18.2/24 brd 10.0.18.255 scope global eth0
valid_lft forever preferred_lft forever
#互ping
#192.168.132.131容器/ # ping 10.0.18.2
PING 10.0.18.2 (10.0.18.2): 56 data bytes64 bytes from 10.0.18.2:
seq=0 ttl=62 time=2.517 ms64 bytes from 10.0.18.2:
seq=1 ttl=62 time=1.058 ms64 bytes from 10.0.18.2:
seq=2 ttl=62 time=1.676 ms192.168.132.132容器
PING 10.0.4.2 (10.0.4.2): 56 data bytes64 bytes from 10.0.4.2:
seq=0 ttl=62 time=2.606 ms64 bytes from 10.0.4.2:
seq=1 ttl=62 time=1.727 ms
两主机的容器可以互通
此时的网络数据包流向如图:
- 在dokcer-server1的busybox容器中查看路由表
2. 回到dokcer-server1真机上,查看路由条目
3. 查看arp列表
C : arp的缓存条目
CM: arp的静态条目
4. 查看mac地址 ce:2a:b6:dd:d6:3d的数据流向
[root@docker-server1 ~]# bridge fdb show
可以看到,如果是发向ce:2a:b6:dd:d6:3a的地址,则目标机器在192.168.100.208机器上。则数据就会流转到192.168.100.208上了。经过vxlan封包后的数据包就会经过eth0设备发向到192.168.100.208上。
3.8 配置backend为host-gw
host-gw bakcend是flannel的另一个backend。与vxlan不同,host-gw不会封装数据包,而是在主机的路由表中创建到其他主机的subnet的路由条目,从而实现容器网络跨主机通信。需要说明的是,host-gw不能跨宿主机网络通信,或者说跨宿主机网络通信需要物理路由支持。性能最好
修改etcd如下:
[root@docker-server1 ~]# etcdctl --endpoints http://127.0.0.1:2379 set /coreos.com/network/config '{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "host-gw"}}'
{"Network": "10.0.0.0/16", "SubnetLen": 24, "SubnetMin": "10.0.1.0","SubnetMax": "10.0.20.0", "Backend": {"Type": "host-gw"}
重启flanneld与docker:
root@docker-server1 ~]# kill -9 86780
[root@docker-server1 ~]# /usr/bin/flanneld --etcd-endpoints="http://192.168.132.131:2379" --iface=192.168.132.131 --etcd-prefix=/coreos.com/network &
[root@docker-server1 ~]# systemctl restart docker
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:3e:dd:55:81 brd ff:ff:ff:ff:ff:ff
inet 10.0.4.1/24 brd 10.0.4.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:3eff:fedd:5581/64 scope link
valid_lft forever preferred_lft forever
123: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether 8e:b1:37:26:b0:59 brd ff:ff:ff:ff:ff:ff
inet 10.0.4.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::8cb1:37ff:fe26:b059/64 scope link
valid_lft forever preferred_lft forever
[root@docker-server2 ~]# kill -9 74050
[root@docker-server2 ~]# /usr/bin/flanneld --etcd-endpoints="http://192.168.132.131:2379" --iface=192.168.132.132 --etcd-prefix=/coreos.com/network &
[root@docker-server2 ~]# systemctl restart docker
[root@docker-server2 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:63:fd:11 brd ff:ff:ff:ff:ff:ff
inet 192.168.132.132/24 brd 192.168.132.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::6a92:62ba:1b33:c93d/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:50:67:ff:90 brd ff:ff:ff:ff:ff:ff
inet 10.0.18.1/24 brd 10.0.18.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:50ff:fe67:ff90/64 scope link
valid_lft forever preferred_lft forever
14: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether 62:b9:76:44:bf:32 brd ff:ff:ff:ff:ff:ff
inet 10.0.18.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::60b9:76ff:fe44:bf32/64 scope link
valid_lft forever preferred_lft forever
可以在宿主机上查看到路由条目
[root@docker-server1 ~]# ip route
default via 192.168.132.2 dev ens33 proto static metric 100
10.0.0.0/16 dev flannel.1
10.0.4.0/24 dev docker0 proto kernel scope link src 10.0.4.1
10.0.18.0/24 via 192.168.132.132 dev ens33
172.17.0.0/16 dev br-b1c2d9c1e522 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-ec4a8380b2d3 proto kernel scope link src 172.18.0.1
172.22.16.0/24 dev br-f42e46889a2a proto kernel scope link src 172.22.16.1
192.168.132.0/24 dev ens33 proto kernel scope link src 192.168.132.131 metric 100
扩展
calico网络
- bgp转发:相当于host-gw转发。不能跨网段进行转发
- ipip转发:相当于vxlan转发模式
cailco优势:
- 同时开启了两种转发模式,但是flannel只能开启其中一种转发模式
- 自动判断,如果宿主机跨网段,就是用ipip的方式转发,如果没有跨网段,就使用bgp方式转发
- 有流量策略管理,控制流量
ovs:openvswitch,openshift使用的网络