Docker 网络模型以及容器通信
本篇接着上篇:【Docker 网络及原理探究】,继续深入探究容器网络通信原理,通过学习 Docker 网路驱动模型,更好地解决容器间的通信问题🎉🎉
1、Docker 的网络驱动模型
1.1、Docker 的网络驱动模型分类:
bridge
:Docker 中默认的网络驱动模型,在启动容器时如果不指定则默认为此驱动类型;host
:打破 Docker 容器与宿主机之间的网络隔离,直接使用宿主机的网络环境,该模型仅适用于 Docker17.6 及以上版本;overlay
:可以连接多个 docker 守护进程或者满足集群服务之间的通信;适用于不同宿主机上的 docker 容器之间的通信;macvlan
:可以为 docker 容器分配MAC
地址,使其像真实的物理机一样运行;none
:即禁用了网络驱动,需要自己手动自定义网络驱动配置;plugins
:使用第三方网络驱动插件;
1.2、Docker 网络模式
查看 docker 网络
docker network ls
Docker 内置这三个网络,运行容器时,你可以使用该--network
标志来指定容器应连接到哪些网络。
该bridge
网络代表docker0
所有 Docker 安装中存在的网络。除非你使用docker run --network=<NETWORK>
选项指定,否则 Docker 守护程序默认将容器连接到此网络。
我们在使用docker run
创建 Docker 容器时,可以用 --net
选项指定容器的网络模式,Docker 可以有以下 4 种网络模式:
host模式
:使用--net=host
指定。none模式
:使用--net=none
指定。bridge模式
:使用--net=bridge
指定,默认设置。container模式
:使用--net=container:NAME_or_ID
指定。
2、容器通信问题
由于不同容器通过
veth pair
连接在虚拟网桥docker0
上,所以容器之间可以通过IP
互相通信,但是无法通过容器名进行通信。docker0 不支持容器名连接访问默认网桥
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/hosts
配置文件(本地 DNS 解析),缺点是手动配置较为繁杂;用户自定义 bridge 网桥,这是目前解决此类问题的主要方法,提供更好的隔离效果和更好的互通性(更好的隔离效果是针对外界网络,而更好的互通性则是指同一
bridge
下的不同容器之间),用户自定义 bridge 在容器之间提供了自动 DNS 解析。
容器在默认情况下以隔离方式运行,它们完全不知道同一计算机上有其他进程或容器。 那么,如何使容器能够彼此通信? 答案就是网络连接。 如果两个容器在同一网络上,那么它们可彼此通信。 如果没在同一网络上,则没法通信。
3、容器之间通信的主要方式总结
3.1、通过容器 ip 访问
容器重启后,ip 会发生变化。通过容器 ip 访问不是一个好的方案。
3.2、通过宿主机的 ip:port 访问
通过宿主机的ip:port
访问,只能依靠监听在暴露出的端口的进程来进行有限的通信。
3.3、通过--link
建立连接(官方不推荐使用)
原理分析:
运行容器时,指定参数 link,使得源容器与被链接的容器可以进行相互通信,并且接受的容器可以获得源容器的一些数据,比如:环境变量。
与
/etc/hosts
中的主机条目不同,如果重新启动源容器,则不会自动更新存储在环境变量中的 IP 地址。我们建议使用主机条目/etc/hosts
来解析链接容器的 IP 地址。除了环境变量之外,Docker 还将源容器的主机条目添加到
/etc/hosts
文件中。(本质上就是通过--link
参数,自动的给容器添加hosts
配置)
--link
建立连接步骤:✨
启动 tomcat01,tomcat02
--link
通过配置/etc/hosts
实现连接通过
link
建立连接的容器,被链接的容器能 ping 通源容器,反过来不行。被链接容器会继承源容器的环境变量信息
建立
link
连接
tomcat02
容器 link 到 tomcat03
上
查看 tomcat03 hosts 配置
3.4、🧨通过 User-defined networks(推荐)
用户自定义网桥步骤:✨
创建用户自定义 bridge 网桥
删除网桥:
docker network rm test-network
把之前启动的 mysql01,centos01,centos02 容器加入到自定义 bridge 网桥中:
connect
查看自定义 bridge 网桥信息
通过容器名或别名互连通信
进入 centos01 容器,ping centos02
, ping mysql01
可以发现 centos01 可以和 centos02、mysql01 容器之间可以通信
断开网络
由于我们的容器仍然连接着默认 bridge 网桥 docker0,而现在我们已经不需要它,所以应该将容器与 docker0 的连接断开,执行以下操作disconnect
:
查看默认 bridge 网桥 docker0 的容器网络配置
最后
了解了 Docker 网络、容器通信之后,对继续学习服务网格(Service Mesh
)与Kubernetes
的服务发现有很大帮助。很多的项目架构也都是从网络通信角度进行的层级、模块划分(比如:网路拓扑图、终极系统架构异地多活)。关于网络,学完之后你会发现很多东西都串一块了,超级有意思😊
微信公众号:【看见另一种可能】
我是 甜点cc
热爱前端,也喜欢专研各种跟本职工作关系不大的技术,技术、产品兴趣广泛且浓厚,等待着一个创业机会。本号主要致力于分享个人经验总结,希望可以给一小部分人一些微小帮助。
希望能和大家一起努力营造一个良好的学习氛围,为了个人和家庭、为了我国的互联网物联网技术、数字化转型、数字经济发展做一点点贡献。数风流人物还看中国、看今朝、看你我。
版权声明: 本文为 InfoQ 作者【甜点cc】的原创文章。
原文链接:【http://xie.infoq.cn/article/8c9a0b3b284a8933ce43f1d6e】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论