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

探索 Docker bridge 的正确姿势 小白亲测有效!

  •  
  •   daocloud ·
    DaoCloud · 2017-03-02 13:21:43 +08:00 · 2604 次点击
    这是一个创建于 2815 天前的主题,其中的信息可能已经有所发展或是发生改变。

    上一回合,小白折腾了 Docker 架构,铁要趁热我开始学习 Docker 容器网络。此刻的心情,是激动的,也是不安的。激动是因为终于要面对 Docker 的第一座大山 :网络,不安是因为网络问题一直以来都是小白的软肋,那些年我们一起学过的网络知识,如今。。。

    硬着头皮翻开《 Docker 进阶与实战》开始 Docker 网络初探,里面讲述了 Docker 容器网络的好几种模式。其中 “ bridge “ 模式成功的吸引了我的注意。 bridge 模式俗称桥接模式,关于它的定义小白早就忘了,但不难理解的是 bridge 的作用,bridge 可以连接不同的东西

    早期的二层网络中, bridge 可以连接不同的 LAN 网,如下图所示。当主机 1 发出一个数据包时, LAN 1 的其他主机和网桥 br0 都会收到该数据包。网桥再将数据包从入口端复制到其他端口上(本例中就是另外一个端口)。因此, LAN 2 上的主机也会接收到主机 A 发出的数据包,从而实现不同 LAN 网上所有主机的通信。

    随着网络技术的发展,传统 bridge 衍生出适用不同应用场景的模式,其中最典型要属 Linux bridge 模式,它是 Linux Kernel 网络模块的一个重要组成部分,用以保障不同虚拟机之间的通信,或是虚拟机与宿主机之间的通信,如下图所示 :

    依葫芦画瓢, Docker bridge 十有八九是用来连接不同容器,或是连接容器与宿主机的。

    带着疑问,我快速浏览了这个章节,结果是大惊从早到晚失色,书中的介绍比我预想的复杂很多, Docker bridge 模式不仅使用了 veth pair技术,还使用了网络命名空间技术,更令我吃惊的是, Docker bridge 模式下竟然采用了 NAT方式。 Docker bridge 和 Linux bridge 二者,初看如出一辙,再看又相去甚远,还真是傻傻分不清楚。没想到我的容器网络学习计划,刚起步便遭遇了滑铁卢。

    没有搞清楚 Docker bridge 与 Linux bridge 的区别前,这书简直没法看了。依小白的经验,云里雾里的时候摸清楚基本概念最有效,先从 Linux bridge 模式的基本工作原理入手,再从 Docker bridge 模式下的 “黑科技” ( veth pair 、网络命名空间技术、 NAT )入手 ,或许能找出点头绪。压抑住内心的愤懑,我翻开了《深入理解 LINUX 网络技术的内幕》,找寻这些关键字的足迹。

    Linux bridge 模式

    Linux bridge 模式下, Linux Kernel 会创建出一个 虚拟网桥,用以实现主机网络接口虚拟网络接口间的通信。从功能上来看, Linux bridge 像一台虚拟交换机,所有桥接设置的虚拟机分别连接到这个交换机的一个接口上,接口之间可以相互访问且互不干扰,这种连接方式对物理主机而言也是如此。

    在桥接的作用下,虚拟网桥会把主机网络接口接收到的网络流量转发给虚拟网络接口,于是后者能够接收到路由器发出的 DHCP (动态主机设定协议,用于获取局域网 IP )信息及路由更新。这样的工作流程,同样适用于不同虚拟网络接口间的通信。具体的实现方式如下所示:

    虚拟机与宿主机通信: 用户可以手动为虚拟机配置 IP 地址、子网掩码,该 IP 需要和宿主机 IP 处于同一网段,这样虚拟机才能和宿主机进行通信。

    虚拟机与外界通信: 如果虚拟机需要联网,还需为它手动配置网关,该网关也要和宿主机网关保持一致。

    除此之外,还有一种较为简单的方法,那就是虚拟机通过 DHCP 自动获取 IP ,实现与宿主机或宿主机以外的世界通信,小白亲测有效。

    Docker bridge 模式

    大致清楚 Linux bridge 模式后,再来看 Docker bridge 模式,小白也有了信心。再次翻开《 Docker 进阶与实战》,仔细阅读后小白了解到在该 bridge 模式下, Docker Daemon 会创建出一个名为 docker0 的虚拟网桥,用来连接宿主机容器,或者连接不同的容器,书中的介绍与小白之前的假设也不谋而合。

    Docker 利用 veth pair [注释 1]技术,在宿主机上创建了两个虚拟网络接口 veth0 和 veth1 ( veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会无条件地传输给另一方)。

    容器与宿主机通信 : 在桥接模式下, Docker Daemon 将 veth0 附加到 docker0 网桥上,保证宿主机的报文有能力发往 veth0 。再将 veth1 添加到 Docker 容器所属的网络命名空间[注释 2],保证宿主机的网络报文若发往 veth0 可以立即被 veth1 收到。

    容器与外界通信 : 容器如果需要联网,则需要采用 NAT [注释 2] 方式。准确的说,是 NATP (网络地址端口转换) 方式。 NATP 包含两种转换方式: SNAT 和 DNAT 。

    • 目的 NAT (Destination NAT , DNAT): 修改数据包的目的地址。

    当宿主机以外的世界需要访问容器时,数据包的流向如下图所示:

    由于容器的 IP 与端口对外都是不可见的,所以数据包的目的地址为 宿主机ip端口,为 192.168.1.10:24 。

    数据包经过路由器发给宿主机 eth0 ,再经 eth0 转发给 docker0 网桥。由于存在 DNAT 规则,会将数据包的目的地址转换为容器ip端口,为 172.17.0.n:24 。

    宿主机上的 docker0 网桥识别到容器 ip 和端口,于是将数据包发送附加到 docker0 网桥上的 veth0 接口, veth0 接口再将数据包发送给容器内部的 veth1 接口,容器接收数据包并作出响应。

    • 源 NAT (Source NAT , SNAT): 修改数据包的源地址。

    当容器需要访问宿主机以外的世界时,数据包的流向为下图所示:

    此时数据包的源地址为容器ip端口,为 172.17.0.n:24 ,容器内部的 veth1 接口将数据包发往 veth0 接口,到达 docker0 网桥。

    宿主机上的 docker0 网桥发现数据包的目的地址为外界的 IP 和端口,便会将数据包转发给 eth0 ,并从 eth0 发出去。由于存在 SNAT 规则,会将数据包的源地址转换为宿主机ip端口,为 192.168.1.10:24 。

    由于路由器可以识别到宿主机的 ip 地址,所以再将数据包转发给外界,外界接受数据包并作出响应。这时候,在外界看来,这个数据包就是从 192.168.1.10:24 上发出来的, Docker 容器对外是不可见的。

    ##小结

    小白的容器网络学习只是刚刚开了头,竟也能折腾出这么多玩儿意,有 veth pair ,有网络命名空间, 还有 NAT 。虽说 docker bridge 模式仅仅是容器网络的冰山一角,后面的学习之路仍然且行且艰辛,但小白也掌握了一些学习经验,那就是面对错综复杂的网络模式,首先需要识其筋骨胜肉,抓住本质含义。小白就是凭着对 bridge 的理解,才展开了一系列大胆的假设,带着问题最终在书中得到求证。 Disappointing, but not fatal 。

    [注释 1] veth pair 是用于不同 network namespace 间进行通信的方式, veth pair 将一个 network namespace 数据发往另一个 network namespace 的 veth 。

    [注释 2] 网络命名空间是用于隔离网络资源(/proc/net 、 IP 地址、网卡、路由等)。由于一个物理的网络设备最多存放在一个网络命名空间中,所以通过 veth pair 在不同的网络命名空间中创建通道,才能达到通信的目的。

    [注释 3] NAT 为网络地址转换( Network Address Translation )的缩写,是一种在 ip 数据包通过路由器或防火墙时重写来源 ip 地址或目的 ip 地址的技术。

    作者介绍 | Evelyn

    DaoCloud 容器技术开源团队成员,曾在 Intel DCG 部门担任 Cloud Engineering, 对分布式调度框架 Mesos 有深入学习,对集群资源管理有一定经验,目前致力于 Docker 容器技术的研究和实践。 Evelyn 所在的容器技术开源团队,在 DaoCloud 主要负责容器生态的开源工作。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5321 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 49ms · UTC 07:57 · PVG 15:57 · LAX 23:57 · JFK 02:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.