本质上来说容器间的网络通讯和计算机间通讯是一样的。
一、Docker 容器网络模型
1.1、两个容器网络如何互通
Docker 各个容器通过 namespace 进行了隔离,其中包括网络隔离,各容器间的网络信息配置等互不影响。
等同于真实世界中的物理计算机,不同在于物理计算机通过物理网卡进行网络隔离。
在真实世界中,两台物理计算机最简单的通讯方式就是通过一条网线进行直连,通过网卡转发数据包实现网络通讯。
在容器中也是类似的方式,不同的是容器中的网卡和网线都是虚拟的。
对于 Linux 系统,通常使用 Linux veth pair(Linux 虚拟网卡对)来实现两个不同的 network namespace ,即两个不同容器间的网络通讯,如图:
两个容器分别对应两个虚拟的网卡Veth1和 Veth2 ,两个网卡之间通过虚拟的网线直连,从而实现两个容器间的网络通讯。
1.2、多容器网络互通
在真实世界中,通常需要进行网络通讯的物理计算机是很多的,点对点的布线方式是不合理的,同样的也会浪费资源,如:网线等。对于这些问题,从而衍生出了不同类型的网络拓扑结构,如:总线型、环状型、星型。
针对这些复杂结构,从而衍生除了不同的网络设备,交换机,路由器。
多容器间的通讯同样采用的相同的方式,不同在于容器使用的软件模拟的交换机,路由器进行多容器的网络通讯。
对于 Linux系统来说,Linxu 通过 Linux Bridge通过软件的方式模拟实现了交换机的功能,从而实现多容器间的通讯,如图:
1.3、Docker 容器网络模型
Docker 容器网络模型,即 Docker 通过软件方式实现容器通讯的网络模型。同时 Docker 提供了 Docker Engine 模块管理整个 docker 网络,如下图:
Docker 通过对已有的 Linxu 技术进行封装,实现自己的网络模型,从而实现容器间、容器与宿主机,容器与外部网络的通讯。
Docker 网络模型中,提出了几个抽象概念:Network Sandbox、Network、Endpoint、NetWork Driver 等。
1.3.1、Docker 核心网络模型

Docker 核心网络模型由三个部分组成
- Network Sandbox(网络沙盒)
Network sandBox是每个容器运行的网络环境,该网络是每个容器独享。
其通过 Linux 的 Namespace 进行网络隔离实现,隔离了包括端口套接字、IP路由表、防火墙等内容。
- Network(网络)
Docker 中的 Network 模块通过构建虚拟子网实现了Docker 容器间的网络通讯。
不过 Network构建的虚拟网络和宿主机网络存在隔离关系,其主要功能目的是形成容器间的安全通讯。
- Endpoint(端点)
Endpoint就是虚拟网卡对中的其中一个网卡端点,它位于容器或网络隔离墙上,是一个内外网络通讯的出入口。
通过配对容器 Endpoint 和网络Endpint,构建桥梁完成网络通讯
1.3.2、Network Drivers
上面提到了 Docker 核心网络模型定了容器内部网络的通信模型。在核心网络模型下对应的是 Docker Enginer ,而Docker Enginer 是整个Docker 运行的核心,它也负责进行网络管理。
Docker 中的除了内部容器间的网络通讯,还支持与宿主机,以及外网通讯的能力,针对不同的网络需求 Docker 提供了不同的网络方案,针对不同的场景 Docker 提供了插件式,可拔插的方式提供网络驱动支持。
默认情况下,Docker 支持的网络驱动
前面提到了 Docker 针对网络管理提供了可拔插式的驱动程序,下面简单介绍并对比下几种网络驱动
2.1、Bridge Driver

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

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

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 容器信息
# docker inspect mysql_1--------------"Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"NetworkID": "74a076c2xxxxxx","EndpointID": "d4b49c95fdb95edxxxx","Gateway": "172.17.0.1","IPAddress": "172.17.0.2","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"MacAddress": "02:42:ac:11:00:02","DriverOpts": null}}--------------
查看 redis 容器信息
# docker inspect redis1----------------"Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"NetworkID": "74a076c2xxx","EndpointID": "cc3e0e70395f58e363c16xxx","Gateway": "172.17.0.1","IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"MacAddress": "02:42:ac:11:00:03","DriverOpts": null}}----------------
结论
默认都是 bridge 网络,且在同一个 Docker 所虚拟的子网中。
