本质上来说容器间的网络通讯和计算机间通讯是一样的。

一、Docker 容器网络模型

1.1、两个容器网络如何互通

Docker 各个容器通过 namespace 进行了隔离,其中包括网络隔离,各容器间的网络信息配置等互不影响。
等同于真实世界中的物理计算机,不同在于物理计算机通过物理网卡进行网络隔离。

在真实世界中,两台物理计算机最简单的通讯方式就是通过一条网线进行直连,通过网卡转发数据包实现网络通讯。

在容器中也是类似的方式,不同的是容器中的网卡和网线都是虚拟的。

对于 Linux 系统,通常使用 Linux veth pair(Linux 虚拟网卡对)来实现两个不同的 network namespace ,即两个不同容器间的网络通讯,如图:
image.png
两个容器分别对应两个虚拟的网卡Veth1Veth2 ,两个网卡之间通过虚拟的网线直连,从而实现两个容器间的网络通讯。

1.2、多容器网络互通

在真实世界中,通常需要进行网络通讯的物理计算机是很多的,点对点的布线方式是不合理的,同样的也会浪费资源,如:网线等。对于这些问题,从而衍生出了不同类型的网络拓扑结构,如:总线型、环状型、星型。
针对这些复杂结构,从而衍生除了不同的网络设备,交换机,路由器。

多容器间的通讯同样采用的相同的方式,不同在于容器使用的软件模拟的交换机,路由器进行多容器的网络通讯。

对于 Linux系统来说,Linxu 通过 Linux Bridge通过软件的方式模拟实现了交换机的功能,从而实现多容器间的通讯,如图:
image.png

1.3、Docker 容器网络模型

Docker 容器网络模型,即 Docker 通过软件方式实现容器通讯的网络模型。同时 Docker 提供了 Docker Engine 模块管理整个 docker 网络,如下图:
image.png
Docker 通过对已有的 Linxu 技术进行封装,实现自己的网络模型,从而实现容器间、容器与宿主机,容器与外部网络的通讯。

Docker 网络模型中,提出了几个抽象概念:Network SandboxNetworkEndpointNetWork Driver 等。

1.3.1、Docker 核心网络模型

image.png
Docker 核心网络模型由三个部分组成

  • Network Sandbox(网络沙盒)

Network sandBox是每个容器运行的网络环境,该网络是每个容器独享。
其通过 Linux 的 Namespace 进行网络隔离实现,隔离了包括端口套接字、IP路由表、防火墙等内容。

  • Network(网络)

Docker 中的 Network 模块通过构建虚拟子网实现了Docker 容器间的网络通讯。
不过 Network构建的虚拟网络和宿主机网络存在隔离关系,其主要功能目的是形成容器间的安全通讯。

  • Endpoint(端点)

Endpoint就是虚拟网卡对中的其中一个网卡端点,它位于容器或网络隔离墙上,是一个内外网络通讯的出入口。
通过配对容器 Endpoint 和网络Endpint,构建桥梁完成网络通讯

1.3.2、Network Drivers

Docker官方文档

上面提到了 Docker 核心网络模型定了容器内部网络的通信模型。在核心网络模型下对应的是 Docker Enginer ,而Docker Enginer 是整个Docker 运行的核心,它也负责进行网络管理。
Docker 中的除了内部容器间的网络通讯,还支持与宿主机,以及外网通讯的能力,针对不同的网络需求 Docker 提供了不同的网络方案,针对不同的场景 Docker 提供了插件式,可拔插的方式提供网络驱动支持。
默认情况下,Docker 支持的网络驱动

  • bridge
  • host
  • overlay
  • ipvlan
  • macvlan
  • none
  • third-party network plugin

    二、Docker Network Drivers

前面提到了 Docker 针对网络管理提供了可拔插式的驱动程序,下面简单介绍并对比下几种网络驱动

2.1、Bridge Driver

image.png
bridge 是 Docker 默认支持的网络驱动,在需要进行容器间访问时通常也会使用该网络驱动。
Bridge 网络驱动下,容器通过 NetWork Namespace和宿主机完成了网络隔离,在同一个 docker network下所有容器同属于同一个子网中,并分配有子网中对应的IP地址,各容器通过 IP 进行容器间通讯,同时通过 bridge 实现容器和外部网络的通讯。

2.2、Host Driver

image.png
Host Driver 创建的容器,其他资源的占用仍然会通过 namespace 进行隔离,但是网络不会进行隔离。
使用的宿主机的网络,所以可以直接使用宿主机 IP + port 的方式直接访问。(此时容器不在分配容器IP)

2.3、Overlay Driver

Overlay Driver 可以将多个 Docker Daemon(多台装有Docker 进程的主机) 连接在一起,使不同服务器间的容器进行网络通讯。Overlay Driver 消除了装有 Docker Daemon 的不同主机中的容器之间进行操作系统级路由的需要。

2.4、MacLan Driver

Macvlan网络允许您将MAC地址分配给容器,使其显示为网络上的物理设备。Docker守护进程通过容器的MAC地址将流量路由到容器。

2.5、None Driver

image.png

None Driver 创建的容器拥有独立的 Network Namespace ,不过容器不进行任何网络配置,不进行任何网络通讯。

2.6、third-pard Driver

2.6.1、flannel

2.6.2、weave

2.6.3、calico

三、管理网络

容器能够相互连接的前提是两者处于一个网络中(这里的网络是指容器网络模型中的网络)。这里的网络指的是 Docker 所虚拟的子网。
将容器网络沙盒(sanbox)看做虚拟主机,只有当多个主机在同一子网中,才嫩能够相互进行网络数据交换。

在 Docker 中,启动的 Docker 服务默认 bridge 网络,在不专门指定网络的情况下,所有容器连接到同一个子网中。

验证

docker 启动一个简易的 mysql 容器和 redis 容器,通过 docker inspect 验证观点

查看 mysql 容器信息

  1. # docker inspect mysql_1
  2. --------------
  3. "Networks": {
  4. "bridge": {
  5. "IPAMConfig": null,
  6. "Links": null,
  7. "Aliases": null,
  8. "NetworkID": "74a076c2xxxxxx",
  9. "EndpointID": "d4b49c95fdb95edxxxx",
  10. "Gateway": "172.17.0.1",
  11. "IPAddress": "172.17.0.2",
  12. "IPPrefixLen": 16,
  13. "IPv6Gateway": "",
  14. "GlobalIPv6Address": "",
  15. "GlobalIPv6PrefixLen": 0,
  16. "MacAddress": "02:42:ac:11:00:02",
  17. "DriverOpts": null
  18. }
  19. }
  20. --------------

查看 redis 容器信息

  1. # docker inspect redis1
  2. ----------------
  3. "Networks": {
  4. "bridge": {
  5. "IPAMConfig": null,
  6. "Links": null,
  7. "Aliases": null,
  8. "NetworkID": "74a076c2xxx",
  9. "EndpointID": "cc3e0e70395f58e363c16xxx",
  10. "Gateway": "172.17.0.1",
  11. "IPAddress": "172.17.0.3",
  12. "IPPrefixLen": 16,
  13. "IPv6Gateway": "",
  14. "GlobalIPv6Address": "",
  15. "GlobalIPv6PrefixLen": 0,
  16. "MacAddress": "02:42:ac:11:00:03",
  17. "DriverOpts": null
  18. }
  19. }
  20. ----------------

结论

默认都是 bridge 网络,且在同一个 Docker 所虚拟的子网中。