V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hansonwang99
V2EX  ›  程序员

Docker 容器跨主机通信之:直接路由方式

  •  
  •   hansonwang99 ·
    hansonwang99 · 2018-06-14 07:06:02 +08:00 · 3336 次点击
    这是一个创建于 2355 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Desktop



    概述

    就目前 Docker 自身默认的网络来说,单台主机上的不同 Docker 容器可以借助 docker0 网桥直接通信,这没毛病,而不同主机上的 Docker 容器之间只能通过在主机上用映射端口的方法来进行通信,有时这种方式会很不方便,甚至达不到我们的要求,因此位于不同物理机上的 Docker 容器之间直接使用本身的 IP 地址进行通信很有必要。再者说,如果将 Docker 容器起在不同的物理主机上,我们不可避免的会遭遇到 Docker 容器的跨主机通信问题。本文就来尝试一下。



    情景构造

    如下图所示,我们有两个物理主机 1 和主机 2,我们在各自宿主机上启动一个 centos 容器,启动成功之后,两个容器分别运行在两个宿主机之上,默认的 IP 地址分配如图所示,这也是 Docker 自身默认的网络。

    两台主机上的容器如何通信?

    此时两台主机上的 Docker 容器如何直接通过 IP 地址进行通信?

    一种直接想到的方案便是通过分别在各自主机中 添加路由 来实现两个 centos 容器之间的直接通信。我们来试试吧



    方案原理分析

    由于使用容器的 IP 进行路由,就需要避免不同主机上的容器使用了相同的 IP,为此我们应该为不同的主机分配不同的子网来保证。于是我们构造一下两个容器之间通信的路由方案,如下图所示。

    容器间通信

    各项配置如下:

    • 主机 1 的 IP 地址为:192.168.145.128
    • 主机 2 的 IP 地址为:192.168.145.129
    • 为主机 1 上的 Docker 容器分配的子网:172.17.1.0/24
    • 为主机 2 上的 Docker 容器分配的子网:172.17.2.0/24

    这样配置之后,两个主机上的 Docker 容器就肯定不会使用相同的 IP 地址从而避免了 IP 冲突。

    我们接下来 定义两条路由规则 即可:

    • 所有目的地址为 172.17.1.0/24 的包都被转发到主机 1 上
    • 所有目的地址为 172.17.2.0/24 的包都被转发到主机 2 上

    综上所述,数据包在两个容器间的传递过程如下:

    • 从 container1 发往 container2 的数据包,首先发往 container1 的“网关” docker0,然后通过查找主机 1 的路由得知需要将数据包发给主机 2,数据包到达主机 2 后再转发给主机 2 的 docker0,最后由其将数据包转到 container2 中;反向原理相同,不再赘述。

    我们心里方案想的是这样,接下来实践一下看看是否可行。



    实际试验

    • 0x01. 分别对主机 1 和主机 2 上的 docker0 进行配置

    编辑主机 1 上的 /etc/docker/daemon.json 文件,添加内容:"bip" : "ip/netmask"

    { "bip", "172.17.1.252/24" }
    

    编辑主机 2 上的 /etc/docker/daemon.json 文件,添加内容:"bip" : "ip/netmask"

    { "bip", "172.17.2.252/24" }
    
    • 0x02. 重启 docker 服务

    主机 1 和主机 2 上均执行如下命令重启 docker 服务以使修改后的 docker0 网段生效

    systemctl restart docker
    
    • 0x03. 添加路由规则

    主机 1 上添加路由规则如下:

    route add -net 172.17.2.0 netmask 255.255.255.0 gw 192.168.145.129
    

    主机 2 上添加路由规则如下:

    route add -net 172.17.1.0 netmask 255.255.255.0 gw 192.168.145.128
    
    • 0x04. 配置 iptables 规则

    主机 1 上添加如下规则:

    iptables -t nat -F POSTROUTING
    iptables -t nat -A POSTROUTING -s 172.17.1.0/24 ! -d 172.17.0.0/16 -j MASQUERADE
    

    主机 2 上添加如下规则:

    iptables -t nat -F POSTROUTING
    iptables -t nat -A POSTROUTING -s 172.17.2.0/24 ! -d 172.17.0.0/16 -j MASQUERADE
    
    • 0x05. 启动容器

    主机 1 上启动 centos 容器:

    docker run -it --name container1 centos /bin/bash
    

    主机 2 上启动 centos 容器:

    docker run -it --name container2 centos /bin/bash
    
    • 0x06. 容器间直接通信

    好了,现在两容器可以互 ping 了

    container1 ping container2

    container2 ping container1



    后记

    本文探讨了局域网中不同宿主机间 Docker 容器直接通信的一种可能方案。当然现在实现跨主机容器间通信的现成方案也很多,典型的比如 flannel 这种,我的 个人私有云 也用的是这种方案。

    如果有兴趣,也可以抽点时间看看作者一些关于容器化、微服务化方面的文章:



    9 条回复    2018-06-14 16:17:09 +08:00
    AllOfMe
        1
    AllOfMe  
       2018-06-14 07:52:25 +08:00 via Android
    谢谢,收藏了
    xenme
        2
    xenme  
       2018-06-14 08:10:14 +08:00 via iPhone   ❤️ 1
    正规不应该是 overlay network 么
    新一点的支持 macvlan 可以直用

    最后才是楼主这。
    renothing
        3
    renothing  
       2018-06-14 08:17:53 +08:00   ❤️ 1
    手动去添加路由这显然不 docker。
    楼主干的事儿,实际上就是 Flannel 干的活儿
    hansonwang99
        4
    hansonwang99  
    OP
       2018-06-14 08:55:30 +08:00 via iPhone
    @renothing 可以
    jinhan13789991
        5
    jinhan13789991  
       2018-06-14 09:38:25 +08:00
    这不就是基本的路由规则嘛~ 其实和 docker 没什么关系吧。
    我还以为在 docker 内部实现的~
    rrfeng
        6
    rrfeng  
       2018-06-14 09:41:53 +08:00 via Android
    直接路由为啥还有 nat ?你不是在逗我?
    zhengxiaowai
        7
    zhengxiaowai  
       2018-06-14 10:08:26 +08:00
    一直以来都是自由两种方法:
    一种是通过宿主机,就是你这种,这行方式性能好。
    还有一种就是通过虚拟网桥实现,这种方式功能多。
    hansonwang99
        8
    hansonwang99  
    OP
       2018-06-14 10:38:13 +08:00 via iPhone
    向列为大拿致敬
    alexsunxl
        9
    alexsunxl  
       2018-06-14 16:17:09 +08:00
    @rrfeng 默认模式,docker 和宿主机有一层 nat 不是正常的吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2558 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:39 · PVG 23:39 · LAX 07:39 · JFK 10:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.