• Docker 容器跨主机通信 - Flannel


    image-20220909094036787

    Author:rab



    前言

    今天是中秋佳节,首先在此祝大家“中秋快乐,阖家团圆”。

    今天我们要讲的一个内容就是 Docker 容器跨主机的通信方案,我们都知道,在 Docker Swarm、K8s 领域中均涉及到了容器间的通信问题。而 Docker 容器跨主机通信本身就有很多方式,其中就包括了其原生网络 Overlay 和 MacVlan 方案及第三方网络方案,如 Flannel、Calico 和 Weave 等网络通信方案,今天我们就来看看 Flannel 是到底是如何实现通信的(重点是掌握原理)。

    一、架构及环境

    1、容器通信架构

    Etcd-Flannel-Docker

    2、实验环境

    Hostserverversion备注
    192.168.56.120Docker、Flannel23.0.6、0.22.3Docker 服务、Flannel 网络
    192.168.56.121Docker、Flannel23.0.6、0.22.3Docker 服务、Flannel 网络
    192.168.56.122Etcd3.4.27Etcd 服务

    这里为了快速实验,我们的 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    image-20230920160207562

    2、编写配置文件

    mkdir /data/etcd/data && mkdir /etc/etcd && vim /etc/etcd/etcd.conf
    
    • 1
    #[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"
    
    • 1
    • 2
    • 3
    • 4
    • 5

    参数说明:

    # 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”
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、配置 systemd 管理

    vim /lib/systemd/system/etcd.service
    
    • 1
    [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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    启动并设置开机自启动

    systemctl start etcd.service
    systemctl enable etcd.service
    systemctl status etcd.service
    
    • 1
    • 2
    • 3

    image-20230920162318703

    可正常数据读写!

    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(后端):要使用的后端类型和该后端的特定配置。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    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
    
    • 1
    • 2
    • 3
    • 4

    5、数据验证

    etcdctl get /docker/network/config
    
    • 1

    image-20230921103528805

    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/
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、配置 systemd 管理

    mk-docker-opts.sh:运行后会将 flannel 获取的网络参数写入 /run/flannel/subnet.env 文件

    vim /lib/systemd/system/flanneld.service
    
    • 1
    [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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3、启动 flannel

    必须先提前保证 etcd 启动正常,才能使 flannel 获取正确地址段,docker 容器才能从 flannel 获取唯一地址。

    systemctl daemon-reload
    systemctl start flanneld.service
    systemctl enable flanneld.service
    systemctl status flanneld.service
    
    • 1
    • 2
    • 3
    • 4

    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
    
    • 1
    [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
    ...
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、启动 Docker

    systemctl daemon-reload
    systemctl start docker.service
    systemctl enable docker.service
    systemctl status docker.service
    
    • 1
    • 2
    • 3
    • 4

    3、此时看看服务器就多了一个 flannel 的虚拟网卡

    其 IP 正是我们 flannel 配置文件中指定的 IP 段,此时 docker0 的 IP 也发生了变化,因为上面我们修改了 docker 服务的启动参数。

    image-20230921104106895

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

    3.1 通信验证

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

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

    image-20230921110641057

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

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

    image-20230921110710154

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    当然也能正常访问外网(如百度、京东等)!

    3.2 路由转发分析

    我们以 120 上的路由规则来讲解。

    image-20230921115939498

    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

  • 相关阅读:
    MongoDB单机集群方案及详解
    java-php-python--数字相册管理系统-点赞演示2021计算机毕业设计
    GaussDB SQL基础语法示例-常见的条件表达式
    【无标题】
    MATLAB算法实战应用案例精讲-【目标检测】YOLOV5(补充篇)
    Selenium隐藏浏览器和元素截屏实践
    故障分析 | Redis Cluster 分片内存异常使用不均问题诊断
    让我们进入面向对象的世界(二)
    MCU编译时间模板 永久适用
    【人工智能】神经网络八股
  • 原文地址:https://blog.csdn.net/IT_ZRS/article/details/133418378