张磊:浅谈容器网络( 三 )


张磊:浅谈容器网络
文章图片
需要注意的是 , 在实际的数据传递时 , 上述数据的传递过程在网络协议栈的不同层次 , 都有Linux内核Netfilter参与其中 。 所以 , 如果感兴趣的话 , 你可以通过打开iptables的TRACE功能查看到数据包的传输过程 , 具体方法如下所示:
#在宿主机上执行$iptables-traw-AOUTPUT-picmp-jTRACE$iptables-traw-APREROUTING-picmp-jTRACE
通过上述设置 , 你就可以在/var/log/syslog里看到数据包传输的日志了 。 这一部分内容 , 你可以在课后结合iptables的相关知识进行实践 , 从而验证我和你分享的数据包传递流程 。
熟悉了docker0网桥的工作方式 , 你就可以理解 , 在默认情况下 , 被限制在NetworkNamespace里的容器进程 , 实际上是通过VethPair设备+宿主机网桥的方式 , 实现了跟同其他容器的数据交换 。
与之类似地 , 当你在一台宿主机上 , 访问该宿主机上的容器的IP地址时 , 这个请求的数据包 , 也是先根据路由规则到达docker0网桥 , 然后被转发到对应的VethPair设备 , 最后出现在容器里 。 这个过程的示意图 , 如下所示:
张磊:浅谈容器网络
文章图片
同样地 , 当一个容器试图连接到另外一个宿主机时 , 比如:ping10.168.0.3 , 它发出的请求数据包 , 首先经过docker0网桥出现在宿主机上 。 然后根据宿主机的路由表里的直连路由规则(10.168.0.0/24viaeth0)) , 对10.168.0.3的访问请求就会交给宿主机的eth0处理 。
所以接下来 , 这个数据包就会经宿主机的eth0网卡转发到宿主机网络上 , 最终到达10.168.0.3对应的宿主机上 。 当然 , 这个过程的实现要求这两台宿主机本身是连通的 。 这个过程的示意图 , 如下所示:
张磊:浅谈容器网络
文章图片
所以说 , 当你遇到容器连不通“外网”的时候 , 你都应该先试试docker0网桥能不能ping通 , 然后查看一下跟docker0和VethPair设备相关的iptables规则是不是有异常 , 往往就能够找到问题的答案了 。
不过 , 在最后一个“Docker容器连接其他宿主机”的例子里 , 你可能已经联想到了这样一个问题:如果在另外一台宿主机(比如:10.168.0.3)上 , 也有一个Docker容器 。 那么 , 我们的nginx-1容器又该如何访问它呢?
这个问题 , 其实就是容器的“跨主通信”问题 。
在Docker的默认配置下 , 一台宿主机上的docker0网桥 , 和其他宿主机上的docker0网桥 , 没有任何关联 , 它们互相之间也没办法连通 。 所以 , 连接在这些网桥上的容器 , 自然也没办法进行通信了 。
不过 , 万变不离其宗 。
如果我们通过软件的方式 , 创建一个整个集群“公用”的网桥 , 然后把集群里的所有容器都连接到这个网桥上 , 不就可以相互通信了吗?
说得没错 。
这样一来 , 我们整个集群里的容器网络就会类似于下图所示的样子:
张磊:浅谈容器网络
文章图片
可以看到 , 构建这种容器网络的核心在于:我们需要在已有的宿主机网络上 , 再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络 。 所以 , 这种技术就被称为:OverlayNetwork(覆盖网络) 。
而这个OverlayNetwork本身 , 可以由每台宿主机上的一个“特殊网桥”共同组成 。 比如 , 当Node1上的Container1要访问Node2上的Container3的时候 , Node1上的“特殊网桥”在收到数据包之后 , 能够通过某种方式 , 把数据包发送到正确的宿主机 , 比如Node2上 。 而Node2上的“特殊网桥”在收到数据包后 , 也能够通过某种方式 , 把数据包转发给正确的容器 , 比如Container3 。