几天前,为了解决平常在本地进行平常工做和开发测试之间的矛盾,利用docker在Windows系统中搭建了基于Linux的测试环境:借助Docker,在win10下编码,一键在Linux下测试。在这边文章里主要介绍了如何在本地经过docker构建与生产环境基本一致的环境并一键运行、测试咱们的代码。Docker官方建议每一个容器中只运行一个服务[1],可是咱们的项目多是由多个服务组成,在服务中可能会须要mysql、redis等中间件的支持,因此一般咱们将一个项目的不一样服务划分到不一样容器中。这种作法虽然具备低耦合、高隔离性等优势,可是也增长了服务之间通讯的复杂度。mysql
Docker容器间的通讯方式根据媒介能够分为:volume共享通讯
、网络通讯
等;根据通讯范围也能够分为:同主机通讯
和跨主机通讯
等。而本文主要针对容器间的网络通讯方法进行讨论。redis
Docker的网络驱动模型分类:sql
以上是Docker支持的几种网络驱动模型,它们都具备独特的特色和应用范围,为了更加详细地了解Docker的网络运行原理,下面挑选几种较为重要的网络模型进行研究。docker
如上图所示为Docker中bridge
驱动模式的示意图,其中蓝色的模块表示主机上的网卡。当Docker启动时会自动在主机上建立一个虚拟网桥docker0
,使用默认网络模式建立docker容器时会自动建立一对儿veth pair
接口,一端链接在docker容器中(如图容器中的eth0
),一端链接在虚拟网桥docker0
上(如图veth
)。这种veth pair
是一种虚拟网络设备,主要用于不一样namespace中(意味着网络隔离)的网络通讯,它老是成对存在的。在这里能够把它想象成一对儿靠虚拟网线链接起来的两个虚拟网卡,一端链接着docker容器,一端链接着虚拟网桥docker0
。shell
经过这种方式,不一样docker容器之间能够经过ip地址互相通讯,也能够经过虚拟网桥访问主机上的网络eth0
(添加iptables规则,将docker容器对目标地址发出的访问经过地址假装的方式修改成主机对目标地址进行访问)。后端
若是想要外界网络访问docker容器时,须要在docker容器启动时加上参数'-p [主机端口]:[容器端口]'进行端口映射,原理也是经过修改iptables规则将访问[主机端口]的数据转发到docker容器的[容器端口]中,可是这种作法也存在着占用主机有限的端口资源的缺点。安全
在主机上经过命令docker network ls
能够查看docker中存在的网络:bash
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
网桥,这是目前解决此类问题的主要方法;
用户自定义bridge相对于使用默认bridge的主要优点:
更好的隔离效果
是针对外界网络,而更好的互通性
则是指同一bridge
下的不一样容器之间。仍是以以前的分别部署了Web服务和mysql服务的两个容器container一、container2为例,container1只须要对外界网络暴露Web服务的80
端口,而负责后端的container2只需与container1互连,不须要对外暴露,有效地保护了后端容器的安全性,提升了容器对外的隔离效果。而同属于用户自定义bridge
的容器container一、container2之间自动将全部端口暴露,方便容器间进行无障碍的通讯,而不会遭受到外界的意外访问。建立用户自定义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服务器了。
断开网络: 因为咱们的容器仍然链接着默认bridgedocker0
,而如今咱们已经不须要它,因此应该将容器与docker0
的链接断开,执行如下操做:
# 断开容器与docker0的链接
docker network disconnect bridge test_demo
docker network disconnect bridge mysqld5.7
复制代码
关键字:跨主机通讯、集群
Run multiple services in a container. docs.docker.com/config/cont… ↩︎