Docker 网络模型
Docker 容器为了实现网络隔离,可以看作连接在不同虚拟网卡上的主机。网络隔离的基本需求是不同虚拟主机直接网络不能够互通,虚拟主机可以访问外部设备,而外部设备不能够直接访问虚拟主机,只能够通过端口来访问。
根据链来分
- FORWARD 拦截所有非本地流量,所有 docker 流量都被包含在这里。下图,ISO 是隔离不同网桥之间的互相访问。由于已经过滤掉了不同隔离网络之间的访问,所以 docker 链中是接受所有外界的流量到 docker 网卡中。再往下两条是允许虚拟网卡流量流向主机外部和网卡本身。
 - OUTPUT 和PREROUTING链则是截获所有本地非容器流量,他们都公用 DOCKER 链,如果发现是要访问host:port,将其 DNAT 到对应的容器地址。
 - POSTROUTING 链是将所有容器访问主机外的流量,伪装成本地流量。

单机网桥模式
单机网桥模式是没有指定任何网络选项的容器,假设容器的虚拟 ip 为 172.10.0.x,由于该网段宿主机并没有暴露给外界,因此外界无法访问容器。但有一种例外情况,就是外界主机通过修改路由表强行将 172.10.0.x 的流量转发给宿主机。这样流量在到达宿主机后是可以匹配到一条路由规则的,从而实现外界流量访问虚拟容器。
容器内部的出流量在宿主机的 POST 链做了 MASQUERADE 处理,所以可以访问外界。假设容器的虚拟 ip 为 172.10.0.x,容器所有的出流量都会经过宿主机的 OUTPUT 和 POSTROUTING 链后选择合适的网卡进行转发。根据 docker 设置的 iptables 规则,所有出流量在 POSTROUTING 链经过 MASQUERADE 的 SNAT 伪装成为宿主机流量。tcp 回路的时候,宿主机会发现该数据包经历过 SNAT 规则转发,自动将回包的地址修改为 172.10.0.x,经过本地的路由规则转发到 docker0 网桥后就可以发送给对应的虚拟容器。
网桥模式
网桥模式即使用 -p 选项进行端口映射来启动的容器。单机网桥模式会复用主机端的端口,外部流量通过宿主机的 ip 地址加对应的端口号来访问虚拟容器。因此流量只要是到达主机的对应端口,就默认一定是访问主机端的服务。只用端口来判断流量是否走向 docker 容器就可以了。
- 外部流量入:外部流量需要走 PREROUTING-FORWARD-POSTROUTIN 链,外部流量的网卡是除了docker自带的网卡之外的所有网卡。所以这些流量都需要在 PREROUTING 做 DNAT 处理,将流量的目的地址修改为 docker 容器的网段。
- 经过 DNAT 后,宿主机发现流量流向地址不是本地应用,转发到 FORWARD 和 POSTROUTING,并且根据路由表转发到容器对应的虚拟网卡里面。
- 内部流量出:docker 容器出流量也是宿主机应用出流量,所以会从 docker 虚拟网卡发送到 OUTPUT 链,需要在 OUTPUT 链中进行 MASQUERADE 将发送到外部的流量全部 SNAT 为宿主机的地址;此外,还要将发送给本机暴露出的端口也进行 SNAT 处理,即自访问。
- 不同网桥之间的隔离操作:一个网桥发送给其他网桥的流量不会 SNAT 和 DNAT,会被直接发送到虚拟网卡上。虚拟网卡的入链同样会走 PRE 链,检测到是虚拟网卡流量,直接不进行操作。放行到 FORWARD,检测到不同网桥之间的相互访问,由 ISO1 截获,由 ISO2 丢弃。
- 用户安全性操作:所有外部流量在截获前,都会被DOCKER-USER 链截获,用户需要将自己的链接入 DOCKER-USER 链中。
网桥模式中,主要是通过匹配端口号来实现外部流量的转发的,内部流量的流出过程与单机网桥模式是相同的。除此此外,网桥模式下还需要对不同 docker 网络段之间的流量进行隔离操作,防止没有连接的两个虚拟网络段之间相互通信。
DNS 服务器
对于使用了 network 选项启动的容器,docker 会自动使用 127.0.0.11 来创建一个 DNS 服务器,所有 docker 创建出的进程会使用该地址作为默认的 DNS 服务器。并且每一个服务名都会作为一个域名进行注册。该内嵌的 DNS 服务器会根据容器的网段地址来进行选择性查询,从而来实现不同网络驱动之间的域名隔离。
ROUTING MESH模式
该模式的意思是,从任何一个宿主机上暴露端口访问,都可以被负载均衡到任一台宿主机的容器上。

- 外部流量入口:所有的外部流量都会被 PREROUTING 中的 DOCKER-INGRESS 链截获。如果流量目标端口是一个使用 overlay 网络模式的容器,那么该流量会被捕获到 172.18.0.2 容器中。
- ingress-sbox:用来进行第二步iptables 流量控制。这里是通过mark+ipvs的方式来完成的,ipvs 的 vip 被绑定到overlay-bridge上。FORWARD 和 INPUT 链都会对不同端口数据包进行不同的标记,当数据包通过 INPUT 进入ipvs的vip 时,根据不同的标记进行负载均衡。
- 目标容器:直接对流量进行处理。
- 容器流量出口:vxlan 流量出来经过容器后,会经重定向发送到挂在宿主机的虚拟网卡。此时,网卡会被 OUTPUT链截获,如果发现是发送给 overlay 网络的流量,则会被 DNAT 到 ingress-box中。注意,docker_gwbridge 没有做外部 DNAT,无法被外部访问。
- 以上是实现了overlay网络与普通网络流量之间的隔离。这个隔离是使用一个容器来完成的。