内容简介:几天前,为了解决日常在本地进行日常工作和开发测试之间的矛盾,利用docker在Windows系统中搭建了基于Linux的测试环境:Docker容器间的通信方式根据媒介可以分为:Docker的网络驱动模型分类:
几天前,为了解决日常在本地进行日常工作和开发测试之间的矛盾,利用 docker 在Windows系统中搭建了基于 Linux 的测试环境: 借助Docker,在win10下编码,一键在Linux下测试 。在这边文章里主要介绍了如何在本地通过docker构建与生产环境基本一致的环境并一键运行、测试我们的代码。Docker官方建议每个容器中只运行一个服务,但是我们的项目可能是由多个服务组成,在服务中可能会需要 mysql 、 redis 等中间件的支持,所以通常我们将一个项目的不同服务划分到不同容器中。这种做法虽然具有低耦合、高隔离性等优点,但是也增加了服务之间通信的复杂度。
Docker容器间的通信方式根据媒介可以分为: volume共享通信
、 网络通信
等;根据通信范围也可以分为: 同主机通信
和 跨主机通信
等。而本文主要针对容器间的网络通信方法进行讨论。
1. Docker的网络驱动模型
Docker的网络驱动模型分类:
- bridge :Docker中默认的网络驱动模型,在启动容器时如果不指定则默认为此驱动类型;
- host :打破Docker容器与宿主机之间的网络隔离,直接使用宿主机的网络环境,该模型仅适用于Docker17.6及以上版本;
- overlay :可以连接多个docker守护进程或者满足集群服务之间的通信;适用于不同宿主机上的docker容器之间的通信;
- macvlan :可以为docker容器分配MAC地址,使其像真实的物理机一样运行;
- none :即禁用了网络驱动,需要自己手动自定义网络驱动配置;
- plugins :使用第三方网络驱动插件;
以上是Docker支持的几种网络驱动模型,它们都具有独特的特点和应用范围,为了更加详细地了解Docker的网络运行原理,下面挑选几种较为重要的网络模型进行研究。
2. bridge
2.1 docker的默认网桥
如上图所示为Docker中 bridge
驱动模式的示意图,其中蓝色的模块表示主机上的网卡。当Docker启动时会自动在主机上创建一个虚拟网桥 docker0
,使用默认网络模式创建docker容器时会自动创建一对儿 veth pair
接口,一端连接在docker容器中(如图容器中的 eth0
),一端连接在虚拟网桥 docker0
上(如图 veth
)。这种 veth pair
是一种虚拟网络设备,主要用于不同namespace中(意味着网络隔离)的网络通信,它总是成对存在的。在这里可以把它想象成一对儿靠虚拟网线连接起来的两个虚拟网卡,一端连接着docker容器,一端连接着虚拟网桥 docker0
。
通过这种方式,不同docker容器之间可以通过ip地址互相通信,也可以通过虚拟网桥访问主机上的网络 eth0
(添加iptables规则,将docker容器对目标地址发出的访问通过 地址伪装 的方式修改为主机对目标地址进行访问)。
如果想要外界网络访问docker容器时,需要在docker容器启动时加上参数'-p [主机端口]:[容器端口]'进行端口映射,原理也是通过修改iptables规则将访问[主机端口]的数据转发到docker容器的[容器端口]中,但是这种做法也存在着占用主机有限的端口资源的缺点。
在主机上通过命令 docker network ls
可以查看docker中存在的网络:
docker network ls # 输出结果: NETWORK ID NAME DRIVER SCOPE e79b7548b225 bridge bridge local 666d5f1f459d host host local d0d785cf4794 none null local 复制代码
然后通过命令 docker network inspect bridge
查看bridge网络的详细配置:
docker network inspect bridge # 输出结果: [ { "Name": "bridge", "Id": "e79b7548b225c3c80d0f70d0de0b5911ed70a7f39ac20f75a8ae71c5cef05b3a", "Created": "2019-05-17T13:01:27.6581642Z", "Scope": "local", "Driver": "bridge", # bridge驱动模式 "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", # 子网,docker容器的IP范围 "Gateway": "172.17.0.1" # 网关,即docker0 } ] }, ... 省略 ... # 两个docker容器(一个mysql容器,一个Web服务容器)的网络配置 "Containers": { # mysql容器 "d6f33e9bbd60e10d02dd2eebea424a7fc129d9646c96742ec3fe467833017679": { "Name": "mysqld5.7", "EndpointID": "32e900f33367e3570c416c43a5618bd7a742cf94f36799e92895951ed1784736", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", # 容器的IP "IPv6Address": "" }, # 基于tornado的Web服务容器 "dd292d535d16bbfe5382e29486756f4dddfea8e9b10af769db61618d739c5c4e": { "Name": "test_demo", "EndpointID": "eaf8e294f7b54aa50c6e6b30ac91f63b1a0ccbc5b56d6fbdcfeacd0471b15eb3", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", # 容器的IP "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ] 复制代码
由上述配置信息可以看出,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
网桥,这是目前解决此类问题的主要方法;
2.2 用户自定义bridge
用户自定义bridge相对于使用默认bridge的主要优势:
- 用户自定义bridge可以在容器化的应用程序提供更好的 隔离效果 和更好的 互通性 : 这段话看似有些矛盾,但是其中
更好的隔离效果
是针对外界网络,而更好的互通性
则是指同一bridge
下的不同容器之间。还是以之前的分别部署了Web服务和mysql服务的两个容器container1、container2为例,container1只需要对外界网络暴露Web服务的80
端口,而负责后端的container2只需与container1互连,不需要对外暴露,有效地保护了后端容器的安全性,提高了容器对外的隔离效果。而同属于用户自定义bridge
的容器container1、container2之间自动将所有端口暴露,方便容器间进行无障碍的通信,而不会遭受到外界的意外访问。 - 用户自定义bridge在容器之间提供了自动DNS解析: 这也是本文讨论的重点,不同于默认bridge只能通过IP互连的限制,用户自定义的bridge自动提供了容器间的DNS解析功能,容器间可以通过容器名或别名进行通信。
2.2.1 如何使用用户自定义bridge
-
创建用户自定义bridge:
docker network create my-net # 创建了一个名为"my-net"的网络 复制代码
-
将Web服务容器和mysql服务容器加入到"my-net"中,并观察变化:
docker network connect my-net test_demo # 将Web服务加入my-net网络中 docker network connect my-net mysqld5.7 # 将mysql服务加入my-net网络中 复制代码
# 查看my-net的网络配置 docker network inspect my-net # 输出结果(省略部分内容): [ { "Name": "my-net", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Config": [ { "Subnet": "172.18.0.0/16", # my-net的子网 "Gateway": "172.18.0.1" # my-net的网关 } ] }, "Containers": { "d6f33e9bbd60e10d02dd2eebea424a7fc129d9646c96742ec3fe467833017679": { "Name": "mysqld5.7", "EndpointID": "7d0e8d70bb523cceb4d2d8d4e3f8231fc68332c70f7f9b4e5d4abccce2b31a65", "MacAddress": "02:42:ac:12:00:03", "IPv4Address": "172.18.0.3/16", # mysql服务容器的IP,与之前不同 "IPv6Address": "" }, "dd292d535d16bbfe5382e29486756f4dddfea8e9b10af769db61618d739c5c4e": { "Name": "test_demo", "EndpointID": "f7802f1af81e258f77e227609dfdcdf66c49f19776381eb8b0dca6d9e794ccad", "MacAddress": "02:42:ac:12:00:02", "IPv4Address": "172.18.0.2/16", # Web服务容器的IP,与之前不同 "IPv6Address": "" } }, } ] 复制代码
如上所示,用户自定义网络
my-net
的子网为"172.18.0.0/16",所以两docker容器在my-net
网络中的IP分别为:"172.18.0.3/16"、"172.18.0.2/16",与之前的"172.17.0.2/16"、"172.17.0.3/16"不同。 -
通过容器名或别名互连: 进入到Web服务器container1中连接container2:
ping mysqld5.7 -c 3 # 输出结果: PING mysqld5.7 (172.18.0.3) 56(84) bytes of data. 64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.066 ms 64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.145 ms 64 bytes from mysqld5.7.my-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.143 ms --- mysqld5.7 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2048ms rtt min/avg/max/mdev = 0.066/0.118/0.145/0.036 ms 复制代码
如上所示,我们已经可以通过容器名"mysqld5.7"连接mysql服务器了。
-
断开网络: 由于我们的容器仍然连接着默认bridge
docker0
,而现在我们已经不需要它,所以应该将容器与docker0
的连接断开,执行以下操作:# 断开容器与docker0的连接 docker network disconnect bridge test_demo docker network disconnect bridge mysqld5.7 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 跨主机容器通信
- Docker容器化部署尝试——多容器通信(node + mongoDB + nginx)
- Kubernetes之POD、容器之间的网络通信
- 网络通信2:TCP简单通信
- 网络通信3:TCP交互通信
- 如何在ASP.NET Core中使用SignalR构建与Angular通信的实时通信应用程序
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解C#(第3版)
斯基特 (Jon Skeet) / 姚琪琳 / 人民邮电出版社 / 2014-4-1 / 99.00元
本书是世界顶级技术专家“十年磨一剑”的经典之作,在C#和.NET领域享有盛誉。与其他泛泛介绍C#的书籍不同,本书深度探究C#的特性,并结合技术发展,引领读者深入C#的时空。作者从语言设计的动机出发,介绍支持这些特性的核心概念。作者将新的语言特性放在C#语言发展的背景之上,用极富实际意义的示例,向读者展示编写代码和设计解决方案的最佳方式。同时作者将多年的C#开发经验与读者分享,读者可咀其精华、免走弯......一起来看看 《深入理解C#(第3版)》 这本书的介绍吧!
HTML 编码/解码
HTML 编码/解码
html转js在线工具
html转js在线工具