作者:ellen.sun
链接:http://blog.daocloud.io/docker-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 地址的技术。

Docker bridge探索的更多相关文章

  1. Docker bridge br0 pipework

    Docker Centos7 下建立 Docker 桥接网络 - weifengCorp - 博客园https://www.cnblogs.com/weifeng1463/p/7468497.html ...

  2. Docker bridge、host、container other、overlay 网络模式

    docker run创建Docker容器时,可以用--net 选项指定容器的网络模式,Docker有以下5种网络模式: bridge模式:使用–net =bridge指定,默认设置: host模式:使 ...

  3. [头脑风暴] 解读Docker Bridge网络模型

    背景 这几天在研究Kubernetes, 遇到一个有意思的nodejs镜像:luksa/kubia # 不带端口映射启动容器docker run -it -d luksa/kubia# 连接到默认的B ...

  4. 云计算核心技术Docker的探索

    首先通过一个简单的场景来看一下为什么Docker这么火? 开发人员在开发的时候是有一套开发环境,包括运行的操作系统,依赖的服务比如WebLogic.Java,一些特定的配置,比如JVM大小.字符集,操 ...

  5. docker bridge 到 k8s pod 跨节点网络通信机制演进

  6. Docker 网络之理解 bridge 驱动

    笔者在前文<Docker 网络之进阶篇>中介绍了 CNM(Container Network Model),并演示了 bridge 驱动下的 CNM 使用方式.为了深入理解 CNM 及最常 ...

  7. docker网络之bridge

    建议阅读本文章之前了解一下文章,本文不作bridge的基本介绍 https://blog.csdn.net/u014027051/article/details/53908878/ http://wi ...

  8. 12、Docker的网络--bridge

    单机网络 Bridge Network Host Network None Network 多机网络 Overlay Network 12.1 网络命名空间   启动一个容器 docker run - ...

  9. Docker的单主机容器网络

    作者:杨冬 欢迎转载,也请保留这段声明.谢谢! 出处: https://andyyoung01.github.io/ 或 http://andyyoung01.16mb.com/ 本篇文章主要探索Do ...

随机推荐

  1. Q221 最大正方形

    在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积. 示例: 输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 输出: 4 cla ...

  2. Kibana插件sentinl实现邮件报警

    为什么会突然想用到对日志的异常内容进行邮件报警,是因为在上周公司的线上业务多次出现锁表,开发在优化sql的同时,我也在想是不是可以对日志的异常内容进行检测并实现邮件预警. 在网上查询了一些资料后,决定 ...

  3. JVM内存模型和垃圾回收

    Java开发有个很基础的问题,虽然我们平时接触的不多,但是了解它却成为Java开发的必备基础——这就是JVM.在C++中我们需要手动申请内存然后释放内存,否则就会出现对象已经不再使用内存却仍被占用的情 ...

  4. [PY3]——函数——生成器(yield关键字)

    函数—生成器篇 1. 认识和区分可迭代or生成器 1.1 可迭代对象 当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象 当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代 ...

  5. 对数几率回归法(梯度下降法,随机梯度下降与牛顿法)与线性判别法(LDA)

    本文主要使用了对数几率回归法与线性判别法(LDA)对数据集(西瓜3.0)进行分类.其中在对数几率回归法中,求解最优权重W时,分别使用梯度下降法,随机梯度下降与牛顿法. 代码如下: #!/usr/bin ...

  6. webstorm中sass编译时目录或内容包含中文字符报错

    ruby版本:ruby 2.3.1p112 (2016-04-26 revision 54768) [x64-mingw32] sass版本:Sass 3.4.22 (Selective Steve) ...

  7. PL/SQL之异常

    异常分为预定义异常和用户自定义异常.预定义异常是由系统定义的异常.由于他们已在STANDARD包中预定义了,因此,这些预定义异常可以直接在程序中使用,而不用在预定义部分声明.而用户自定义异常则需要在定 ...

  8. AJAX同步问题

    @using ShippingRen.CommonV2.CloudStorage; @using ShippingRen.Api.ServiceModel.PublicDataEntity.Looku ...

  9. Intent的使用

    1.普通Intent跳转 Intent intent_intent = new Intent(MainActivity.this,IntentActivity.class); startActivit ...

  10. Vim 技巧

    :r 文件名 导入另一文件到当前文件中 :! 命令 可以不退出当前编辑的文本而能执行系统的命令 自定义快捷键 注意这里的^P这个是ctrl + V + P :map ^P I//<ESC> ...