Docker 网络原理初探

Docker 中的网络实现也是耐人寻味的一部分,本文简单描述了这四种网络模式的大体实现方式

初探

Docker 有 4 种网络模式

  • bridge
  • container
  • host
  • none

其中 bridge none 在 clone 时使用了 CLONE_NEWNET flag,但 none 仅做了 NETWORK NAMESPACE 但不进行资源设置分配,因而只能访问 loopback 设备(linux 下是 lo,虚拟网卡)

bridge 模式

这是 Docker 的默认网络模式,也是开发者常用的模式。实现了容器与宿主机、容器与容器间的网络栈隔离。

使用 veth pair 技术,一端接入到某个容器,另一段接入网桥 docker0(bridge),实现大致如下:

  • 创建一对 veth pair,假设为 veth0 和 veth1
  • 将 veth1 接入到 docker0,使得内部通过宿主机可以向外界发数据
  • 将 veth0 接入到容器端,并改名为 eth0。实现互通

docker0

容器分配的 IP 与宿主机所在 IP 不处于同一网段,常用的默认 IP 段是 172.17.0.0/16。 docker0 使用 IP Forward 将容器上的服务暴露出来,将 容器 IP 和 服务端口宿主机的端口 进行绑定。

从容器内部向宿主机外部发送数据

  • 访问时内核为进程分配一个可用的端口
  • 容器内部发送数据通过 eth0(即 veth0) 发送到 veth1(在 docker0 上)
  • docker0 通过 ip forward 将数据包发送到宿主机的 eth0 上
  • 宿主机监测到 iptables 规则,并对其进行 SNAT。将数据包中的源地址替换为宿主机的外网 IP,端口替换为之前绑定到 宿主机的端口
  • 宿主机通过外网向目标 IP 发送数据

容器接收来自宿主机外部的数据

  • 外界向容器绑定在宿主机的 IP端口 发送数据
  • 宿主机收到数据后,因为存在 DNAT 规则。将对接收到的数据包中的 IP 和端口 进行替换为 容器 IP 和端口
  • 因宿主知道目标 IP 是容器的 IP,故向 docker0 发送_修改后_的数据包
  • docker0 通过 veth pair 将数据包发送到制定容器的 eth0 上

实现功能

  • 隔离容器的网络栈
  • 通过 NAT 实现网络互通

缺点

  • 宿主机的网络端口依旧有限,容器还是需要对端口进行竞争
  • NAT 模式位于第三层网络,网络性能降低

container 模式

无需创建 veth pair

创建过程

  • 查找指定容器的 network namespace(假设为 n1)
  • 将本次创建容器的 network namespace 设为 n1

host 模式

与宿主机 共享网络栈

创建过程

  • 创建容器时,clone 不带 CLONE_NEWNET

优点

无需通过 NAT,使容器获得宿主机的网络性能

缺点

共享网络栈,缺少隔离,端口资源争用

none 模式

这种情况下,容器只能访问内部网络,无法与其他容器、宿主机通信

创建过程

  • 创建容器时,clone 传入 CLONE_NEWNET 但不对网络进行配置