概述
大家都知道,通过docker-compose编排的一组docker容器,如果使用的同一个network,那么这些docker之间可以直接通过docker内部的IP进行通讯。
然而在实际应用中,我们将很多服务拆开部署在不同的宿主机上也很实际,比如A主机部署了5个docker,B主机又部署了6个docker,这11个docker之间需要进行网络互相通讯。
有同学会说,docker内部的服务我可以全部使用docker所在宿主机的IP地址进行通讯(每个docker映射端口到宿主机),这样虽然可行,但是提高了我们对服务的配置复杂度。如果你是微服务又使用了eureka这样的注册中心,你就会发现很头疼了(当然没有纯手工解决不了的问题,我们只想简单一点再方便一点)。
有需要的地方就有发明就有创造,覆盖网络是现在网络应用的一大特点,其中包含了很多种软件方案。本文不再赘述,这里我们说一下其中的一个 flannel 是如何通过 etcd(基于key value的存储) 来实现这个需求目标的。
flannel 网络借助 etcd 来实现一个全局的上帝来同步网络信息。
flannel 网络不会创建新的 bridge,而是用默认的 docker0,但创建 flannel 网络会在主机上创建一个虚拟网卡,挂在 docker0 上,用于跨主机通信(你可以把 flannel 理解为一个路由)。
下面有两张来自网络的图片,可以清晰的表达了 docker、flannel、宿主机 之间的网络通讯和数据路由。
从上面两个图中可以很清晰的看出 flannel 所处的位置及担当的角色。
1、首先从宿主机A的一个docker容器中发出一个网络请求。
2、在同一个宿主机上的所有docker在同一个网段中,如果第1步的请求时同网段的,则自然没有什么问题。
3、如果第1步发出的网络请求不在当前docker所处网段,那么数据会被派发到docker0。
4、docker0 通过flannel 可以从 etcd 中找到目标服务所处的宿主机。
5、然后 flannel 通过当前所在的宿主机将数据包发给目标目标服务所处的宿主机。
6、目标宿主机收到请求后,然后一层一层向下路由到目标服务所在的docker容器。
7、然后完成数据处理后响应数据包(网络TCP请求时需要寻址,响应时是原路返回响应)
组件方式让 flannel 多了几分灵活性,它可以使用二层的 VxLAN 隧道来封装数据包完成跨主机通信,也可以使用纯三层的方案来通信,比如 host-gw,只需修改一个配置文件就可以完成转化。
当然,在线上环境,flannel 所依赖的 etcd 应当部署3个节点组成集群以确保高可用。
架构方案
1、三个etcd 组成集群保证高可用(为了方便,本文只安装一个etcd,集群也很简单几乎没有什么坑)
2、两台宿主机分别安装 flannel 和 docker(不管增加多少,都一样操作,两台已经可以完成演示)
操作步骤
一、安装etcd
关于 etcd 集群的安装和配置,可以参考:Docker 搭建 etcd 集群
我们单机安装一个,执行如下命令:
# 主机执行如下命令(注意其中的IP地址为主机的宿主机IP地址 192.168.1.163,节点名称为 node1 也要注意修改,state 状态为new)
docker run -d -p 2379:2379 -p 2380:2380 \
--volume=/opt/CICD/etcd/etcd-data:/etcd-data \
--restart=always \
--name etcd1 quay.io/coreos/etcd \
/usr/local/bin/etcd --name node1 \
--data-dir=/etcd-data \
--advertise-client-urls http://192.168.1.163:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--initial-advertise-peer-urls http://192.168.1.163:2380 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-cluster-token docker-etcd \
--initial-cluster "node1=http://192.168.1.163:2380" \
--initial-cluster-state new
执行命令 curl -L http://127.0.0.1:2379/v2/members
验证安装结果
[root@localhost etcd-data]# curl -L http://127.0.0.1:2379/v2/members
{"members":[{"id":"8e9e05c52164694d","name":"node1","peerURLs":["http://localhost:2380"],"clientURLs":["http://192.168.1.163:2379"]}]}
二、安装 flannel
主机A:192.168.1.163
主机B:192.168.1.164
flannel 的安装非常简单,直接下载二进制文件即可(当然您也可以自己编译)
打开网址 https://github.com/coreos/flannel/releases 下载最新版对应的架构的版本,一般使用 amd64(我的CentOS 7.6)
比如我的下载地址为: https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
然后一顿命令操作如下:
wget https://github.com/coreos/flannel/releases/download/v0.11.0/flannel-v0.11.0-linux-amd64.tar.gz
tar -zxvf flannel-v0.11.0-linux-amd64.tar.gz
记下文件的位置,例如(/opt/flannel/flanneld)
添加一个flannel服务的System单元,简单的就可以。
#编辑文件
vi /usr/lib/systemd/system/flanneld.service
# 内容如下
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/etc/default/flanneld.conf
ExecStart=/opt/flannel/flanneld --ip-masq -etcd-endpoints=${FLANNEL_ETCD_ENDPOINTS} -etcd-prefix=${FLANNEL_ETCD_PREFIX} $FLANNEL_OPTIONS
ExecStartPost=/opt/flannel/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /etc/default/docker
Restart=on-failure
[Install]
WantedBy=multi-user.target
flanneld.service 中引用了1个配置文件,指向了1个配置,的内容如下(一个需要手工配置,一个是自动生成)
/etc/default/flanneld.conf 文件内容(手工配置)
# Flanneld configuration options
# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://192.168.1.163:2379"
# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/flannel/network"
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""
然后编辑文件 vim /usr/lib/systemd/system/docker.service
找到 ExecStart,在前面添加一行 EnvironmentFile=/etc/default/docker
然后在 ExecStart 最后添加变量 $DOCKER_NETWORK_OPTIONS
(注意其他的参数应该是docker在之前相关需要中添加的,你不要动,这个地方只需要添加这个即可)
示例如下:
(省略前面代码)
EnvironmentFile=/etc/default/docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry=192.168.1.163:81 $DOCKER_NETWORK_OPTIONS
(省略后面代码)
配置etcd中关于flannel的key(这个只在安装了etcd的机器上操作)
因为我的etcd是使用的docker,所以使用命令 docker exec -it etcd1 /bin/sh
进入容器后再操作。
/flannel/network/config
这个key与上文 /etc/default/flanneld.conf
中的配置项 FLANNEL_ETCD_PREFIX
是相对应的,错误的话启动 flanneld 服务就会出错!
操作命令示例(这个只需要操作一次即可,也就是说无论你有多少台 flannel 宿主机,只需要首次操作一次即可):
# etcdctl mk /flannel/network/config '{"Network":"172.72.0.0/16", "SubnetMin": "172.72.1.0", "SubnetMax": "172.72.254.0"}'
{"Network":"172.72.0.0/16", "SubnetMin": "172.72.1.0", "SubnetMax": "172.72.254.0"}
一切就绪后,重启flannel和docker
systemctl daemon-reload
systemctl start flanneld
systemctl enable flanneld
systemctl restart docker
正常情况下,到 etcd上执行 etcdctl ls /flannel/network/subnets
能够看到 flannel 申请的网段
操作示例:
# etcdctl ls /flannel/network/subnets
/flannel/network/subnets/172.72.5.0-24
在每个 flannel 宿主机上,使用 cat /run/flannel/subnet.env
查看网段信息,自动生成的内容如下:
[root@localhost flannel]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.72.0.0/16
FLANNEL_SUBNET=172.72.95.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=true
在每个 flannel 宿主机上,使用 cat /etc/default/docker
查看自动生成的 docker 的启动参数信息,自动生成的内容如下:
[root@localhost flannel]# cat /etc/default/docker
DOCKER_OPT_BIP="--bip=172.72.95.1/24"
DOCKER_OPT_IPMASQ="--ip-masq=false"
DOCKER_OPT_MTU="--mtu=1472"
DOCKER_NETWORK_OPTIONS=" --bip=172.72.95.1/24 --ip-masq=false --mtu=1472"
同上操作在另外一个宿主机B:192.168.1.164(或更多宿主机)上进行 flannel 配置。
多个宿主机的 flannel 服务都启动后,到 etcd上执行 etcdctl ls /flannel/network/subnets
能够看到多个宿主机的 flannel 都分配了网段。
验证
1、在 flannel 宿主机上使用命令 ifconfig
查看 flannel0 和 docker0 网卡的IP网址在同一个子网,并且和文件 /etc/default/docker
中的子网也一致,即为OK。
例如:
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.72.10.1 netmask 255.255.255.0 broadcast 172.72.10.255
inet6 fe80::42:1eff:feb7:54f prefixlen 64 scopeid 0x20<link>
ether 02:42:1e:b7:05:4f txqueuelen 0 (Ethernet)
RX packets 27 bytes 1400 (1.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 31 bytes 2184 (2.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.164 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::20c:29ff:fe41:47f5 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:41:47:f5 txqueuelen 1000 (Ethernet)
RX packets 1108823 bytes 668271247 (637.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 319511 bytes 33087014 (31.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.72.5.0 netmask 255.255.255.255 destination 172.72.5.0
inet6 fe80::4e7a:2372:11e4:f8d8 prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2 bytes 96 (96.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2、如果网络不对,可能是上面操作不当导致,处理起来很简单,按如下命令操作一遍即可
systemctl daemon-reload
systemctl restart flanneld
systemctl enable flanneld
systemctl restart docker
3、查看具体 docker 容器的IP地址的命令为 docker inspect --format='{{.NetworkSettings.IPAddress}}' ID或NAMES
,或者直接 docker inspect ID或NAMES
看详细信息。
4、在不同的 flannel 宿主机上,分别随便启动一个docker服务,在一个docker中ping另外一个docker的IP地址,即可进行验证,如果你 docker 有http服务,使用 curl
命令请求测试也一样。
(END)