Docker容器间的通信方式根据媒介可以分为:volume共享通信
、网络通信
等;根据通信范围也可以分为:同主机通信
和跨主机通信
等。而本文主要针对容器间的网络通信方法进行讨论。
Docker的网络驱动模型
Docker的网络驱动模型分类:
- bridge:Docker中默认的网络驱动模型,在启动容器时如果不指定则默认为此驱动类型;
- host:打破Docker容器与宿主机之间的网络隔离,直接使用宿主机的网络环境,该模型仅适用于Docker17.6及以上版本;
- overlay:可以连接多个docker守护进程或者满足集群服务之间的通信;适用于不同宿主机上的docker容器之间的通信;
- macvlan:可以为docker容器分配MAC地址,使其像真实的物理机一样运行;
- none:即禁用了网络驱动,需要自己手动自定义网络驱动配置;
- plugins:使用第三方网络驱动插件;
以上是Docker支持的几种网络驱动模型,它们都具有独特的特点和应用范围,为了更加详细地了解Docker的网络运行原理,下面挑选几种较为重要的网络模型进行研究。
清晰明了:Docker的四种网络模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,只有lo 网络接口。需要我们自己为Docker容器添加网卡、配置IP等。
1、closed container 封闭式网络模式
相当于一座孤岛,没有网络协议栈的通信
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,只有lo 网络接口。需要我们自己为Docker容器添加网卡、配置IP等。
示例图如下
2、bridged container 桥接式网络模式
各个容器之间网络协议栈单独分离
当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。
同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口。比如典型的 172.17.42.1,掩码为 255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16)的地址。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
如图所示,同一个主机的两个容器之间通过网桥doker0进行通信。(不同之间的主机上的容器通信需要借助overlay网络,涉及到一些底层协议,单独写一篇文章拿出来讲)
在主机上通过命令**docker network ls
**可以查看docker中存在的网络:
docker network ls
然后通过命令docker network inspect bridge
查看bridge网络的详细配置:
docker network inspect bridge
由上述配置信息可以看出,docker网桥的网关的IP为”172.17.0.1”,也即**docker0
,而docker的子网为”172.17.0.0/16”,docker将会为容器在”172.17.0.0/16”中分配IP,如其中的mysql容器
的IP为”172.17.0.2/16”、test_demo容器
的IP为”172.17.0.3/16”。由于不同容器通过veth pair
连接在虚拟网桥docker0
**上,所以容器之间可以通过IP互相通信,但是无法通过容器名进行通信:
# 在test_demo容器中访问mysqld5.7容器(通过IP)
ping 172.17.0.2 -c 3
# 输出结果:
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.147 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.185 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.209 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2057ms
rtt min/avg/max/mdev = 0.147/0.180/0.209/0.027 ms
# 在test_demo容器中访问mysqld5.7容器(通过容器名)
ping mysqld5.7
# 输出结果:
ping: mysqld5.7: Name or service not known
复制代码
所以,默认的网桥bridge
上的容器只能通过IP互连,无法通过DNS解析名称或别名。假如我们在container1中部署了Web服务,在container2中部署了mysql,container1中的Web服务往往需要连接container2的mysql,这是只能靠IP进行连接,但是docker也无法保证容器重启后的IP地址不变,所以更好的方式是通过别名进行互联,在网络中加入DNS服务器,将容器名与IP地址进行匹配,省去了手动修改Web服务中连接mysql的IP的过程。
为了实现不同容器通过容器名或别名的互连,docker提供了以下几种:
- 在启动docker容器时加入
--link
参数,但是目前已经被废弃,废弃的主要原因是需要在连接的两个容器上都创建--link
选项,当互连的容器数量较多时,操作的复杂度会显著增加; - 启动docker容器后进入容器并修改
/etc/host
配置文件,缺点是手动配置较为繁杂; - 用户自定义
bridge
网桥,这是目前解决此类问题的主要方法;
作者:kk_miles
链接:https://juejin.im/post/5ce26cb9f265da1bcd37aa7c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3、joined container 联合挂载式网络模式
容器之间可以共享网络协议栈,即可以通过套接字来进行通信
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
示例如下图:
4、opentainer container 开放式网络模式
与主机共享网络协议栈
Host模式使用是在容器启动时候指明—network host,此时容器共享宿主机的Network Namespace,容器内启动的端口直接是宿主机的端口,容器不会创建网卡和IP,直接使用宿主机的网卡和IP,但是容器内的其他资源是隔离的,如文件系统、用户和用户组。直接使用宿主机网络。同样启动一个nginx,此时共享主机网络,根据情况来使用,这样子也不用做端口转发,网络传输效率会比较高(思考一下为什么)。