Docker 容器跨主机通信 - Flannel

Docker 容器跨主机通信 - Flannel_第1张图片

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、容器通信架构

Docker 容器跨主机通信 - Flannel_第2张图片

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

Docker 容器跨主机通信 - Flannel_第3张图片

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

Docker 容器跨主机通信 - Flannel_第4张图片

可正常数据读写!

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

Docker 容器跨主机通信 - Flannel_第5张图片

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 服务的启动参数。

Docker 容器跨主机通信 - Flannel_第6张图片

三、容器通信验证及路由分析

3.1 通信验证

1、120 服务器运行测试容器

docker run -it --rm --name test120 busybox

Docker 容器跨主机通信 - Flannel_第7张图片

2、121 服务器运行测试容器

docker run -it --rm --name test121 busybox

Docker 容器跨主机通信 - Flannel_第8张图片

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 上的路由规则来讲解。

Docker 容器跨主机通信 - Flannel_第9张图片

  1. default via 192.168.56.2 dev ens33 proto static metric 100

    默认路由,将所有不在本地子网范围内的数据包发送到网关 192.168.56.2,通过 ens33 网卡进行传输,路由优先级为 100。

  2. 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

  3. 10.2.79.0/24 via 10.2.79.0 dev flannel.1 onlink

    将目标网段 10.2.79.0/24 的数据包通过 flannel.1 网卡传输,网关为 10.2.79.0onlink 表示网关是直接可达的,也就是在同一子网内。

  4. 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 数据分发分析

  1. 容器直接使用目标容器的 ip 访问,默认通过容器内部的eth0发送出去。
  2. 报文通过 veth pair 被发送到 vethXXX。
  3. vethXXX 直接连接到虚拟交换机 docker0 的,报文通过虚拟 bridge docker0 发送出去。
  4. 查找路由表,外部容器 ip 的报文都会转发到 flannel0 虚拟网卡,这是一个 P2P 的虚拟网卡,然后报文就被转发到监听在另一端的 flanneld。
  5. flanneld 通过 etcd 维护了各个节点之间的路由表,把原来的报文 UDP 封装一层,通过配置的 iface 发送出去。
  6. 报文通过主机之间的网络找到目标主机。
  7. 报文继续往上,到传输层,交给监听在 8285 端口的 flanneld 程序处理。
  8. 数据被解包,然后发送给 flannel0 虚拟网卡。
  9. 查找路由表,发现对应容器的报文要交给 docker0。
  10. docker0 找到连到自己的容器,把报文发送过去。

总结

过程其实很简单,重点是掌握理论,如路由转发、数据分发的过程,Flannel 依赖三层 IP 转发,但不会对数据包进行封装,属于 underlay 网络。还有就是实验过程中注意 Docker、Flannel 的启动顺序。

—END

你可能感兴趣的:(Docker,docker,容器,运维)