两个或多个docker容器之间通过名字相互访问
前言
需要部署的项目中有数据库和 Tomcat,Tomcat需要连接到数据库容器的 3306 端口上,由于容器的 IP 地址会变化,又不能写死 IP 地址,所以就有了下文。
docker 网卡介绍
docker 安装好之后默认会创建三个虚拟网卡,可以使用 docker network ls 命令来查看,三个虚拟网卡和 VMware 的类似。
mango@wanzhouyi:~$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
a831f74e2810 bridge bridge local
1d49e8d7b613 es_test bridge local
72e00f5290f2 host host local
5eb25bd2cd37 none null local
mango@wanzhouyi:~$
- bridge 是默认的网卡,网络驱动是 bridge 模式,类似于 Vmware 的 NAT 模式,如果容器启动时不指定网卡,则会默认连接到这块网卡上。如果需要访问容器内部的端口需要设置端口映射。
- host 是直接使用主机的网络,网络驱动是 host 模式,类似于 Vmware 的桥接模式,可能会和主机的端口存在冲突,不需要设置端口映射即可连接到容器端口。
- none 禁止所有联网,没有网络驱动,一般情况下用不到。
由于默认的网卡需要设置端口映射并且 IP 地址会随着容器的启动停止而变动,所以我们这里选择使用自定义网络来实现容器之间互相访问。
创建自定义网络
使用 docker network create my-net 命令来创建一个我们自定义的网络,网络驱动仍然使用 bridge。
mango@wanzhouyi:~$ sudo docker network create my-net
cdf381aba9901c18c31b02cf8c6046b61e1c973bddf64d8469f1c18830a07093
mango@wanzhouyi:~$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
a831f74e2810 bridge bridge local
1d49e8d7b613 es_test bridge local
72e00f5290f2 host host local
cdf381aba990 my-net bridge local
5eb25bd2cd37 none null local
mango@wanzhouyi:~$
现在这个创建好的自定义网络就和默认的 bridge 网络隔离开了,互相之间不能访问,而且它们也不在同一个网段上。
使用 docker network inspect bridge 命令查看默认网卡的详细信息。
mango@wanzhouyi:~$ sudo docker network inspect bridge
[
{
"Name": "bridge",
"Id": "a831f74e2810f7945fc277610dd963e0875c5139916c4784ad5631c7a852247b",
"Created": "2022-10-11T23:44:25.4523466+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
使用 docker network inspect my-net 命令查看自定义网卡的详细信息。
mango@wanzhouyi:~$ sudo docker network inspect my-net
[
{
"Name": "my-net",
"Id": "cdf381aba9901c18c31b02cf8c6046b61e1c973bddf64d8469f1c18830a07093",
"Created": "2022-10-12T01:54:05.6933414+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
对比一下可以看出,默认网卡处于 172.17.0.0/16 这个网段,自定义网卡处于 172.20.0.0/16 这个网段,它们两个肯定是不可以互相通信的。
默认网络和自定义网络区别
说到这里可能有人会问了,那默认的网卡的网卡驱动也是 bridge 模式的,用户自定义的网络也是 bridge 模式,不就是换了一个名字吗,为什么默认的网卡不可以使用别名进行 IP 地址解析呢?
这个问题问得好,官方特意解释了这两个网卡的区别。
User-defined bridges provide automatic DNS resolution between containers.
Containers on the default bridge network can only access each other by IP addresses, unless you use the --link option, which is considered legacy. On a user-defined bridge network, containers can resolve each other by name or alias.
翻译过来大意:就是用户自定义的网卡可以在容器之间提供自动的 DNS 解析,缺省的桥接网络上的容器只能通过 IP 地址互相访问,除非使用 --link 参数。在用户自定义的网卡上,容器直接可以通过名称或者别名相互解析。
文档中提到了 --link 参数,官方文档中已经不推荐使用 --link 参数,并且最终可能会被删除,所以最好不要使用 --link 参数来连接两个容器,并且它有多个缺点。
如果使用 --link 参数,需要在容器之间手动创建链接,这些链接需要双向创建,如果容器多于两个的话,将会很困难。或者也可以通过编辑 hosts 文件的方式来指定解析结果,但是这样将会非常难以调试。
总结
以上就是通过自定义网卡来使两个容器互相连接的方法,这种方法便于部署和调试,而且还提供了网络隔离功能,两个容器之间不会互相干扰,可以随时断开或者连接,并且可以使用 --subnet 参数指定自定义网络的 IP 段,这里就不详细展开了。