Author:rab
目录
- 前言
- 一、架构及环境
- 二、服务部署
- 2.1 Etcd 部署
- 2.2 Flannel 部署
- 2.3 Docker 网络配置
- 三、容器通信验证及路由分析
- 3.1 通信验证
- 3.2 路由转发分析
- 3.3 数据分发分析
- 总结
前言
今天是中秋佳节,首先在此祝大家“中秋快乐,阖家团圆”。
今天我们要讲的一个内容就是 Docker 容器跨主机的通信方案,我们都知道,在 Docker Swarm、K8s 领域中均涉及到了容器间的通信问题。而 Docker 容器跨主机通信本身就有很多方式,其中就包括了其原生网络 Overlay 和 MacVlan 方案及第三方网络方案,如 Flannel、Calico 和 Weave 等网络通信方案,今天我们就来看看 Flannel 是到底是如何实现通信的(重点是掌握原理)。
一、架构及环境
1、容器通信架构
2、实验环境
Host | server | version | 备注 |
---|---|---|---|
192.168.56.120 | Docker、Flannel | 23.0.6、0.22.3 | Docker 服务、Flannel 网络 |
192.168.56.121 | Docker、Flannel | 23.0.6、0.22.3 | Docker 服务、Flannel 网络 |
192.168.56.122 | Etcd | 3.4.27 | Etcd 服务 |
这里为了快速实验,我们的 Etcd 采用单节点的方式部署。
二、服务部署
2.1 Etcd 部署
二进制包下载地址:https://github.com/coreos/etcd/releases
除了二进制方式安装外,还可通过 Docker 方式安装
1、二进制部署
# 复制至shell终端并执行
ETCD_VER=v3.4.27
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz# 配置环境变量
cp /tmp/etcd-download-test/etcd* /usr/bin/# 版本验证
etcd --version
etcdctl version
2、编写配置文件
mkdir /data/etcd/data && mkdir /etc/etcd && vim /etc/etcd/etcd.conf
#[member]
ETCD_NAME="etcd"
ETCD_DATA_DIR="/data/etcd/data"
ETCD_LISTEN_CLIENT_URLS="http://192.168.56.122:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.56.122:2379,http://127.0.0.1:2379"
参数说明:
# ETCD_NAME 节点名称
# ETCD_DATA_DIR 数据目录
# ETCD_LISTEN_CLIENT_URLS 客户端访问监听地址
# ETCD_ADVERTISE_CLIENT_URLS 客户端通告地址
# ETCD_ENABLE_V2
# 在 ETCD v3.4 版本中 ETCDCTL_API=3 和 --enable-v2=false 成为了默认配置
# 如要使用 ETCD v2 版本, 需要 ETCD_ENABLE_V2=true,否则会报错“404 page not found”
3、配置 systemd 管理
vim /lib/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd.service[Service]
Type=notify
ExecStart=/usr/bin/etcd
EnvironmentFile=/etc/etcd/etcd.conf
Restart=on-failure
RestartSec=10
LimitNOFILE=65536[Install]
WantedBy=multi-user.target
启动并设置开机自启动
systemctl start etcd.service
systemctl enable etcd.service
systemctl status etcd.service
可正常数据读写!
4、Etcd 添加网段
vim /data/etcd/flannel-config.json
----------------------------------------------
{
"Network": "10.2.0.0/16",
"SubnetLen": 24,
"SubnetMin": "10.2.1.0",
"SubnetMax": "10.2.254.0",
"Backend":{"Type": "vxlan"}
}
----------------------------------------------
# 参数说明:
# Network(字符串):CIDR格式的IPv4网络,用于整个flannel网络。(这是唯一的强制密钥。)
# SubnetLen(整数):分配给每个主机的子网大小,除非Network小于24,否则默认为24(即/24)。
# SubnetMin(字符串):子网分配应从哪个IP范围开始,默认为第一个子网Network。
# SubnetMax(字符串):子网分配应结束的IP范围的结尾,默认为最后一个子网Network。
# Backend(后端):要使用的后端类型和该后端的特定配置。
etcdctl --endpoints http://192.168.56.122:2379 put /docker/network/config < /data/etcd/flannel-config.json# 如果你在Etcd本地,可以不指定endpoints(远程则需指定,与连接MySQL、Redis一个道理)
etcdctl put /docker/network/config < /data/etcd/flannel-config.json
5、数据验证
etcdctl get /docker/network/config
Etcd 部署完成,第4、5步也验证了读写没问题!
2.2 Flannel 部署
分别在 20、21 上分别进行以下 5 步来部署
1、部署
# 下载二进制包,解压并配置环境变量
tar xzf flannel-v0.22.3-linux-amd64.tar.gz# 配置环境变量
cp flanneld mk-docker-opts.sh /usr/bin/
2、配置 systemd 管理
mk-docker-opts.sh:运行后会将 flannel 获取的网络参数写入
/run/flannel/subnet.env
文件
vim /lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld
Documentation=https://github.com/coreos/flannel
After=network.target
Before=docker.service[Service]
User=root
ExecStartPost=/usr/bin/mk-docker-opts.sh
ExecStart=/usr/bin/flanneld \
-etcd-endpoints=http://192.168.56.122:2379 \
-iface=ens33 \
-ip-masq=true \
-etcd-prefix=/docker/network
Restart=on-failure
Type=notify
LimitNOFILE=65536[Install]
WantedBy=multi-user.target
3、启动 flannel
必须先提前保证 etcd 启动正常,才能使 flannel 获取正确地址段,docker 容器才能从 flannel 获取唯一地址。
systemctl daemon-reload
systemctl start flanneld.service
systemctl enable flanneld.service
systemctl status flanneld.service
2.3 Docker 网络配置
120服务器的 Docker 启动参数添加:
--bip=10.2.23.1/24 --mtu=1450
121服务器的 Docker 启动参数添加:
--bip=10.2.79.1/24 --mtu=1450
注意启动顺序,
Etcd => flannel => Docker
注意的是,要先启动 flannel,这样的话才能根据 flannel 分配到的 IP 来修改 Docker 的启动参数。
1、修改 docker 启动参数
vim /lib/systemd/system/docker.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.2.23.1/24 --mtu=1450
...
...
2、启动 Docker
systemctl daemon-reload
systemctl start docker.service
systemctl enable docker.service
systemctl status docker.service
3、此时看看服务器就多了一个 flannel 的虚拟网卡
其 IP 正是我们 flannel 配置文件中指定的 IP 段,此时 docker0 的 IP 也发生了变化,因为上面我们修改了 docker 服务的启动参数。
三、容器通信验证及路由分析
3.1 通信验证
1、120 服务器运行测试容器
docker run -it --rm --name test120 busybox
2、121 服务器运行测试容器
docker run -it --rm --name test121 busybox
3、互 Ping 连通性验证
# 120 Ping 121
ping 10.2.79.2
PING 10.2.79.2 (10.2.79.2): 56 data bytes
64 bytes from 10.2.79.2: seq=0 ttl=62 time=1.021 ms
64 bytes from 10.2.79.2: seq=1 ttl=62 time=1.897 ms
64 bytes from 10.2.79.2: seq=2 ttl=62 time=2.176 ms
64 bytes from 10.2.79.2: seq=3 ttl=62 time=1.082 ms# 121 Ping 120
ping 10.2.23.3
PING 10.2.23.3 (10.2.23.3): 56 data bytes
64 bytes from 10.2.23.3: seq=0 ttl=62 time=2.494 ms
64 bytes from 10.2.23.3: seq=1 ttl=62 time=1.734 ms
64 bytes from 10.2.23.3: seq=2 ttl=62 time=2.074 ms
64 bytes from 10.2.23.3: seq=3 ttl=62 time=1.913 ms
当然也能正常访问外网(如百度、京东等)!
3.2 路由转发分析
我们以 120 上的路由规则来讲解。
-
default via 192.168.56.2 dev ens33 proto static metric 100
默认路由,将所有不在本地子网范围内的数据包发送到网关
192.168.56.2
,通过ens33
网卡进行传输,路由优先级为 100。 -
10.2.23.0/24 dev docker0 proto kernel scope link src 10.2.23.1
将目标网段
10.2.23.0/24
的数据包通过docker0
网卡传输,源IP地址为10.2.23.1
。 -
10.2.79.0/24 via 10.2.79.0 dev flannel.1 onlink
将目标网段
10.2.79.0/24
的数据包通过flannel.1
网卡传输,网关为10.2.79.0
,onlink
表示网关是直接可达的,也就是在同一子网内。 -
192.168.56.0/24 dev ens33 proto kernel scope link src 192.168.56.120 metric 100
将目标网段
192.168.56.0/24
的数据包通过ens33
网卡传输,源IP地址为192.168.56.120
,路由优先级为100。
字段解释:
proto
:表示路由协议;dev
:表示出接口;src
:表示源IP地址;metric
:表示路由优先级(值越小优先级越高);onlink
:表示网关直接可达;scope link
:表示本地链路,即在同一子网内。
3.3 数据分发分析
- 容器直接使用目标容器的 ip 访问,默认通过容器内部的eth0发送出去。
- 报文通过 veth pair 被发送到 vethXXX。
- vethXXX 直接连接到虚拟交换机 docker0 的,报文通过虚拟 bridge docker0 发送出去。
- 查找路由表,外部容器 ip 的报文都会转发到 flannel0 虚拟网卡,这是一个 P2P 的虚拟网卡,然后报文就被转发到监听在另一端的 flanneld。
- flanneld 通过 etcd 维护了各个节点之间的路由表,把原来的报文 UDP 封装一层,通过配置的 iface 发送出去。
- 报文通过主机之间的网络找到目标主机。
- 报文继续往上,到传输层,交给监听在 8285 端口的 flanneld 程序处理。
- 数据被解包,然后发送给 flannel0 虚拟网卡。
- 查找路由表,发现对应容器的报文要交给 docker0。
- docker0 找到连到自己的容器,把报文发送过去。
总结
过程其实很简单,重点是掌握理论,如路由转发、数据分发的过程,Flannel 依赖三层 IP 转发,但不会对数据包进行封装,属于 underlay 网络。还有就是实验过程中注意 Docker、Flannel 的启动顺序。
—END