两个或多个docker容器之间通过名字相互访问 您所在的位置:网站首页 docker桥接模式 两个或多个docker容器之间通过名字相互访问

两个或多个docker容器之间通过名字相互访问

2023-08-18 21:35| 来源: 网络整理| 查看: 265

前言

由于容器的 IP 地址会在容器重启后发生变化,因不能写死 IP 地址,使用容器的名字访问容器服务是最优的,所以就有了下文。

1.使用 --link 参考

docker run --link可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。

--link的格式:

--link :alias

其中,name和id是源容器的name和id,alias是源容器在link下的别名。

举例:

源容器

创建并启动名为nginx_test的容器。

[root@ambari01 ~]# docker run -d --name nginx_test nginx

接收容器

创建并启动名为node的容器,并把该容器和名为nginx的容器链接起来。

[root@ambari01 ~]# docker run -itd --name node --link nginx_test:nginx centos:7 bash

其中:

--link nginx_test:nginx

nginx_test是上面启动的源容器的名字,nginx是该容器在link下的别名,可省略。

通俗易懂的讲,站在node容器的角度,nginx_test和nginx都是指向提供nginx服务容器的名字,并且作为容器的hostname,node用这2个名字中的任何一个都可以访问到那个容器并与之通信(docker通过DNS自动解析)。我们可以来看下:

进入node容器:

[root@ambari01 ~]# docker exec -it nginx

[root@2398e6006f7e /]#  ping nginx PING nginx (172.17.0.5) 56(84) bytes of data. 64 bytes from nginx (172.17.0.5): icmp_seq=1 ttl=64 time=0.064 ms 64 bytes from nginx (172.17.0.5): icmp_seq=2 ttl=64 time=0.045 ms   [root@2398e6006f7e /]#  ping nginx_test PING nginx (172.17.0.5) 56(84) bytes of data. 64 bytes from nginx (172.17.0.5): icmp_seq=1 ttl=64 time=0.060 ms 64 bytes from nginx (172.17.0.5): icmp_seq=2 ttl=64 time=0.058 ms  

[root@2398e6006f7e /]# ping node ping: node: Name or service not known

当使用--link时,docker会自动在接收容器内创建基于--link参数的环境变量:

docker会在接收容器中设置名为_NAME的环境变量,我们进入node容器,看下此环境变量:

[root@ambari01 ~]# docker exec -it node /bin/bash [root@2398e6006f7e /]#  env | grep -i nginx_name NGINX_NAME=/node/nginx

另外,docker还会在接收容器中创建关于源容器暴露的端口号的环境变量,这些环境变量有一个统一的前缀名称:

PORT_

nginx镜像的Dockerfile文件中暴露了4444端口号:

EXPOSE 80

我们进入node容器,看这些此环境变量:

[root@ambari01 ~]# docker exec -it node /bin/bash

[root@2398e6006f7e /]#  env | grep -i NGINX_PORT_80_TCP_ NGINX_PORT_80_TCP_PROTO=tcp NGINX_PORT_80_TCP_PORT=80 NGINX_PORT_80_TCP_ADDR=172.17.0.5

可见,确实有3个以PORT为前缀的环境变量存在。

另外,docker还在接收容器中创建1个名为_PORT的环境变量,值为源容器的URL:源容器暴露的端口号中最小的那个端口号。

[root@2398e6006f7e /]# env |grep -i  nginx_port= NGINX_PORT=tcp://172.17.0.5:80

注意:

使用--link参数。只能实现docker的单项连接,及只有node容器能连接访问nginx_test容器中服务和域名,而node容器不能访问自身的容器名字,nginx_test容器不能访问自身及node容器的名字。

[root@ambari01 ~]# docker exec -it nginx_test bash

root@4a22c7ed83a9:/# ping nginx_test ping: nginx_test: Name or service not known root@4a22c7ed83a9:/# ping node ping: node: Name or service not known

2.使用自定义网段 docker 网卡介绍

docker 安装好之后默认会创建三个虚拟网卡,可以使用 docker network ls 命令来查看,三个虚拟网卡和 VMware 的类似。

[root@ambari01 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 80c5d482237a bridge bridge local 0d82d44a884a host host local 61dc3dfc2c93 none null local bridge 是默认的网卡,网络驱动是 bridge 模式,类似于 Vmware 的 NAT 模式,如果容器启动时不指定网卡,则会默认连接到这块网卡上。如果需要访问容器内部的端口需要设置端口映射。host 是直接使用主机的网络,网络驱动是 host 模式,类似于 Vmware 的桥接模式,可能会和主机的端口存在冲突,不需要设置端口映射即可连接到容器端口。none 禁止所有联网,没有网络驱动,一般情况下用不到。

由于默认的网卡需要设置端口映射并且 IP 地址会随着容器的启动停止而变动,所以我们这里选择使用自定义网络来实现容器之间互相访问。

创建自定义网络

使用 docker network create my-net 命令来创建一个我们自定义的网络,网络驱动仍然使用 bridge。

[root@ambari01 ~]# docker network ls NETWORK ID          NAME                DRIVER              SCOPE 80c5d482237a        bridge                  bridge                 local 0d82d44a884a        host                     host                    local 4745257203be        my-net                 bridge                 local 61dc3dfc2c93          none                    null                     local [root@ambari01 ~]#

现在这个创建好的自定义网络就和默认的 bridge 网络隔离开了,互相之间不能访问,而且它们也不在同一个网段上。

使用 docker network inspect my-net 命令查看默认网卡的详细信息。

[root@ambari01 ~]# docker network inspect my-net [     {         "Name": "my-net",         "Id": "4745257203be38ff4b886acb4d9c1e1bbb3e5a87c62d08ca396831ae2775c839",         "Created": "2021-10-18T14:50:27.269076493+08:00",         "Scope": "local",         "Driver": "bridge",         "EnableIPv6": false,         "IPAM": {             "Driver": "default",             "Options": {},             "Config": [                 {                     "Subnet": "172.18.0.0/16",                     "Gateway": "172.18.0.1"                 }             ]         }, ......省略         "Options": {},         "Labels": {}     } ]

创建容器

创建两个 python 容器,使用 docker run -it --name test1 --network my-net centos:7 bash 命令来创建第一个名字为 test1 的容器,--name 参数指定容器的名字,--network 参数指定使用自定义的网络。

新开启一个终端,使用 docker run -it --name test2 --network my-net centos:7 bash 命令创建第二个名字为 test2 的容器,尝试使用ping通过别名 test1 来访问第一个容器。

使用 ping 命令测试是可以正常 ping 的通的。

[root@ambari01 ~]# docker run -it --name test2 --network my-net centos:7 bash [root@b2461a7e6fe6 /]# ping test1 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.066 ms 64 bytes from test1.my-net (172.18.0.2): icmp_seq=2 ttl=64 time=0.057 ms [root@b2461a7e6fe6 /]# ping test2 PING test2 (172.18.0.3) 56(84) bytes of data. 64 bytes from b2461a7e6fe6 (172.18.0.3): icmp_seq=1 ttl=64 time=0.021 ms 64 bytes from b2461a7e6fe6 (172.18.0.3): icmp_seq=2 ttl=64 time=0.032 ms  

由于在创建容器时并没有使用 -p 参数设置端口映射,所以外部不能访问到容器内部的内容,但是容器之间全端口都是可以正常访问的。

再次使用 docker network inspect my-net 命令来验证两个容器连接到了同一个自定义网络下。

[root@ambari01 ~]# docker network inspect my-net [     {         "Name": "my-net",         "Id": "4745257203be38ff4b886acb4d9c1e1bbb3e5a87c62d08ca396831ae2775c839",         "Created": "2021-10-18T14:50:27.269076493+08:00",         "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": {             "06c8f14df63e6595a6b1cb8443568680e07e11b37f5089e21f87f02c6bf8224a": {                 "Name": "test1",                 "EndpointID": "2cef43667b03ce1270f76e7f8a933f51f799af1d177cc782714d829dd8390c0e",                 "MacAddress": "02:42:ac:12:00:02",                 "IPv4Address": "172.18.0.2/16",                 "IPv6Address": ""             },             "b2461a7e6fe66cac4c62e5b4aa4c285663f1ef13b59d35407b21c1fbefb8bc22": {                 "Name": "test2",                 "EndpointID": "a2e75b42dc87e7b2eb5f16e309d77ea29af2ba28ca1b75527a5ab4c052bdb7cb",                 "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 文件的方式来指定解析结果,但是这样将会非常难以调试。

默认网卡测试

默认网卡 Name 为bridge ,使用该网段,容器间可以互相通过容器ip访问,但是无法通过容器名字互相访问或者进行自身访问。

总结

以上就是通过自定义网卡来使两个容器互相连接的方法,这种方法便于部署和调试,而且还提供了网络隔离功能,两个容器之间不会互相干扰,可以随时断开或者连接,并且可以使用 --subnet 参数指定自定义网络的 IP 段,这里就不详细展开了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有