前言 需要部署的项目中有数据库和 Tomcat,Tomcat需要连接到数据库容器的 3306 端口上,由于容器的 IP 地址会变化,又不能写死 IP 地址,所以就有了下文。
docker 网卡介绍 docker 安装好之后默认会创建三个虚拟网卡,可以使用 docker network ls
命令来查看,三个虚拟网卡和 VMware 的类似。
1 2 3 4 5 b@ubuntu20:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 68633255abb2 bridge bridge local adea9d9ae839 host host local 517ed92475cc none null local
bridge 是默认的网卡,网络驱动是 bridge 模式,类似于 Vmware 的 NAT 模式,如果容器启动时不指定网卡,则会默认连接到这块网卡上。如果需要访问容器内部的端口需要设置端口映射。 host 是直接使用主机的网络,网络驱动是 host 模式,类似于 Vmware 的桥接模式,可能会和主机的端口存在冲突,不需要设置端口映射即可连接到容器端口。 none 禁止所有联网,没有网络驱动,一般情况下用不到。 由于默认的网卡需要设置端口映射并且 IP 地址会随着容器的启动停止而变动,所以我们这里选择使用自定义网络来实现容器之间互相访问。
创建自定义网络 使用 docker network create my-net
命令来创建一个我们自定义的网络,网络驱动仍然使用 bridge 。
1 2 3 4 5 6 7 8 b@ubuntu20:~$ docker network create my-net 2ee565af7c72d6d4e719471138224496e976d5ea5ee4d00681d597f09c0e6560 b@ubuntu20:~$ docker network ls NETWORK ID NAME DRIVER SCOPE 68633255abb2 bridge bridge local adea9d9ae839 host host local 2ee565af7c72 my-net bridge local 517ed92475cc none null local
现在这个创建好的自定义网络就和默认的 bridge 网络隔离开了,互相之间不能访问,而且它们也不在同一个网段上。
使用 docker network inspect bridge
命令查看默认网卡的详细信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 b@ubuntu20:~$ docker network inspect bridge [ { "Name" : "bridge" , "Id" : "68633255abb265ef682c163b401a810fb66fd08d0cf23f863974e325ad82bbcf" , "Created" : "2020-09-24T02:37:43.329713459Z" , "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
命令查看自定义网卡的详细信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 b@ubuntu20:~$ docker network inspect my-net [ { "Name" : "my-net" , "Id" : "2ee565af7c72d6d4e719471138224496e976d5ea5ee4d00681d597f09c0e6560" , "Created" : "2020-09-24T07:43:14.684477356Z" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : {}, "Config" : [ { "Subnet" : "172.18.0.0/16" , "Gateway" : "172.18.0.1" } ] }, ...后面省略 } ]
对比一下可以看出,默认网卡处于 172.17.0.0/16 这个网段,自定义网卡顺延了一位,处于 172.18.0.0/16 这个网段,它们两个肯定是不可以互相通信的。
创建容器 创建两个 python 容器,使用 docker run -it --name test1 --network my-net python bash
命令来创建第一个名字为 test1 的容器,--name
参数指定容器的名字,--network
参数指定使用自定义的网络, 然后开启一个 python 自带的 HTTP Server。
1 2 3 b@ubuntu20:~$ docker run -it --name test1 --network my-net python bash root@0136e7769fc4:/ Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
新开启一个终端,使用 docker run -it --name test2 --network my-net python bash
命令创建第二个名字为 test2 的容器,尝试使用 curl 通过别名 test1 来访问第一个容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 b@ubuntu20:~$ docker run -it --name test2 --network my-net python bash root@fdbc076a6753:/ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd" > <html> <head > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" > <title>Directory listing for /</title> </head> <body> <h1>Directory listing for /</h1> <hr> <ul> <li><a href=".dockerenv" >.dockerenv</a></li> <li><a href="bin/" >bin/</a></li> <li><a href="boot/" >boot/</a></li> <li><a href="dev/" >dev/</a></li> <li><a href="etc/" >etc/</a></li> <li><a href="home/" >home/</a></li> <li><a href="lib/" >lib/</a></li> <li><a href="lib64/" >lib64/</a></li> <li><a href="media/" >media/</a></li> <li><a href="mnt/" >mnt/</a></li> <li><a href="opt/" >opt/</a></li> <li><a href="proc/" >proc/</a></li> <li><a href="root/" >root/</a></li> <li><a href="run/" >run/</a></li> <li><a href="sbin/" >sbin/</a></li> <li><a href="srv/" >srv/</a></li> <li><a href="sys/" >sys/</a></li> <li><a href="tmp/" >tmp/</a></li> <li><a href="usr/" >usr/</a></li> <li><a href="var/" >var/</a></li> </ul> <hr> </body> </html>
成功返回了 test1 容器的根目录内容,使用 ping 命令测试也是可以正常 ping 的通的。
1 2 3 4 5 6 7 8 root@fdbc076a6753:/ PING test1 (172.18.0.2) 56(84) bytes of data. 64 bytes from test1.my-net (172.18.0.2): icmp_seq=1 ttl=64 time=0.054 ms 64 bytes from test1.my-net (172.18.0.2): icmp_seq=2 ttl=64 time=0.084 ms ^C --- test1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 27ms rtt min/avg/max/mdev = 0.054/0.069/0.084/0.015 ms
由于在创建容器时并没有使用 -p
参数设置端口映射,所以外部不能访问到容器内部的内容,但是容器之间全端口都是可以正常访问的。
再次使用 docker network inspect my-net
命令来验证两个容器连接到了同一个自定义网络下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 b@ubuntu20:~$ docker network inspect my-net [ { "Name" : "my-net" , "Id" : "2ee565af7c72d6d4e719471138224496e976d5ea5ee4d00681d597f09c0e6560" , "Created" : "2020-09-24T07:43:14.684477356Z" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : {}, "Config" : [ { "Subnet" : "172.18.0.0/16" , "Gateway" : "172.18.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "0136e7769fc47b6ef5f0a5d4fe178c043e9228db159bd5bdcc6fbf3097757691" : { "Name" : "test1" , "EndpointID" : "8bd05a32b42f3e675693c7473c4a4883b9e188970bf52aad865a79640557c527" , "MacAddress" : "02:42:ac:12:00:02" , "IPv4Address" : "172.18.0.2/16" , "IPv6Address" : "" }, "fdbc076a675367b2b74c8233fccefcc859a783cbbaedcda382383a9d66d7f6b0" : { "Name" : "test2" , "EndpointID" : "6c19d56dd06cc832af027f425bc65d965b40f508af4fa452725b490dc339e3d8" , "MacAddress" : "02:42:ac:12:00:03" , "IPv4Address" : "172.18.0.3/16" , "IPv6Address" : "" } }, "Options" : {}, "Labels" : {} } ]
在 Containers 字段中可以看到两个容器连接到了同一个网段下,并且自动分配了同网段的 IP 地址。
默认网络和自定义网络区别 说到这里可能有人会问了,那默认的网卡的网卡驱动也是 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 文件的方式来指定解析结果,但是这样将会非常难以调试。
默认网卡测试 接下来验证默认网卡无法使用自动的 DNS 解析。
使用 b@ubuntu20:~$ docker network disconnect my-net test2
和 b@ubuntu20:~$ docker network disconnect my-net test1
命令断开容器和自定义网络的连接。
使用 b@ubuntu20:~$ docker network connect bridge test1
命令和 b@ubuntu20:~$ docker network connect bridge test2
命令将两个容器连接到默认的网卡上,使用 docker network inspect bridge
命令来验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 b@ubuntu20:~$ docker network inspect bridge [ { "Name" : "bridge" , "Id" : "68633255abb265ef682c163b401a810fb66fd08d0cf23f863974e325ad82bbcf" , "Created" : "2020-09-24T02:37:43.329713459Z" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : null, "Config" : [ { "Subnet" : "172.17.0.0/16" , "Gateway" : "172.17.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "0136e7769fc47b6ef5f0a5d4fe178c043e9228db159bd5bdcc6fbf3097757691" : { "Name" : "test1" , "EndpointID" : "3f7f4cbf2123ad8f9bad47a94de5f1b4c51083cddf05e648a2b25b7986a4d14c" , "MacAddress" : "02:42:ac:11:00:02" , "IPv4Address" : "172.17.0.2/16" , "IPv6Address" : "" }, "fdbc076a675367b2b74c8233fccefcc859a783cbbaedcda382383a9d66d7f6b0" : { "Name" : "test2" , "EndpointID" : "d8944f694706729c82571041ec4e01b036b87bf0a224192507242e91a763cb65" , "MacAddress" : "02:42:ac:11:00:03" , "IPv4Address" : "172.17.0.3/16" , "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 exec -it test1 bash
命令进入到 test1 容器中,重新开启 HTTP Server。使用同样的命令进入到 test2 容器中,使用 ping 命令 ping test 是无法解析的状态,curl 也无法访问,我手动结束了请求,证明了以上的说法。
1 2 3 b@ubuntu20:~$ docker exec -it test1 bash root@0136e7769fc4:/ Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
1 2 3 4 5 b@ubuntu20:~$ docker exec -it test2 bash root@fdbc076a6753:/ ^C root@fdbc076a6753:/ ping: test1: Name or service not known
总结 以上就是通过自定义网卡来使两个容器互相连接的方法,这种方法便于部署和调试,而且还提供了网络隔离功能,两个容器之间不会互相干扰,可以随时断开或者连接,并且可以使用 --subnet
参数指定自定义网络的 IP 段,这里就不详细展开了。
本文章首发于个人博客 LLLibra146’s blog 本文作者 :LLLibra146 更多文章请关注:版权声明 :本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!本文链接 :https://blog.d77.xyz/archives/2443eb85.html