【问题标题】:Can't connect to a container in the same host even though the DNS is being resolved即使正在解析 DNS,也无法连接到同一主机中的容器
【发布时间】:2021-06-15 07:11:13
【问题描述】:

我正在尝试从一个容器向同一主机上的另一个容器发出请求。事实证明,请求被拒绝,我无法获得我想要的信息。为了说明,我做了一个小图:

在“机器 1”上,我有 2 个服务在 docker-compose 上运行:App1 有 2 个服务,需要向 App2 发出请求。 App2 是接收请求的服务,只有 1 个服务,监听 4202 端口。

docker-compose.yaml 为 app1

version: '3.9'
    services:
            main_app:
                    build: .
                    depends_on:
                            - db_app
            db_app:
                    restart: always
                    image: redis

docker-compose.yaml 为 app2

version: '3.9'
    services:
            main_app:
                    build: .
                    ports:
                       - "4202:5000"

连接不工作。这很奇怪,因为其他连接工作,例如:

在此图像中,在另一台机器 machine 2 上,我使用 curl 尝试访问在机器 1 内运行的容器。在端口 4202 上,我请求位于内部的域 name.domain.example网络,它由内部 DNS 解析,之后,它确实成功地请求了机器 1 上的容器。

在另一种情况下,我在机器 2 内创建一个容器,并使用 curl 向 name.domain.example 发出请求,结果相同:成功。我可以到达机器 1 内的容器。

在这里,我在机器 1(运行将被请求的服务的同一台机器)上使用 curl。向 name.domain.example 发出请求,并成功到达服务。

在这种情况下,这是请求失败的地方。这一次,我尝试从 app1 容器内发出请求,请求是向 name.domain.example 发出的,DNS 能够解析它,但是当发出请求时,它最终被拒绝了。

在 app1 中,我尝试通过 python 发出请求,来自 requests 库:

import requests

r = requests.get("name.domain.example:4202")
# But, Exception...:
requests.exceptions.ConnectionError: HTTPConnectionPool(host='name.domain.example', port=4202): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f74fbcb1100>: Failed to establish a new connection: [Errno 111] Connection refused'))

我尝试将 app1 放在网络“主机”--network=host 或 docker-composenetwork_mode="host" 上,我可以到达 app2 的容器。但是,这对我的情况没有用处,因为我需要来自 compose 堆栈的其他服务,此外,随着服务的增加和更多地相互依赖,这最终会变成蜘蛛网。

【问题讨论】:

  • 这些图片非常漂亮,但我们真正需要看到的是您的代码——例如您的docker-compose.yml、您提出的确切请求等:-)。或者至少是最小的相关部分。
  • @Don'tPanic 我将编辑问题并显示更多代码。等一下。

标签: docker docker-compose microservices docker-network


【解决方案1】:

这里的技巧是 docker compose 正在为您的每个应用程序创建 docker 网络(或网络命名空间)。尝试运行docker network ls,我敢打赌你会看到类似这样的内容(具体名称会有所不同):

❯ docker network ls
NETWORK ID     NAME                        DRIVER    SCOPE
c6a3be245bd1   bridge                      bridge    local
f8e91845fd46   myapp2_default              bridge    local
677668cbb02b   myapp1_default              bridge    local

默认情况下,这些“桥接”网络都不知道另一个。当您指定 --network=hostnetwork_mode="host" 时,您告诉容器跳过创建 docker/namespace 网络并居住在主机的主命名空间中。从这里他们可以看到你通常可以看到的一切。

所以让我们教这两个组成网络,他们应该互相了解。

首先,我们在 docker-compose 范围之外创建一个 docker 网络:

❯ docker network create myglobalnetwork
6adbd64eed5dd12a2e6d60dffe01b5c222ec4701535322fc17dfeb51aff3b801

我们在 docker-compose 范围之外创建它,因为我们需要在任何一个 docker-compose 范围之外使用它。

我们现在可以更新我们的 docker-compose 配置来引用这个网络。我使用了不同的图像来简化示例,但想法保持不变:

# docker-compose.yml
version: '3.9'
services:
  main_app:
    image: busybox
    command: ping main_app
    depends_on:
      - db_app
    networks:
      - default
      - global
  db_app:
    restart: always
    image: redis
networks:
  global:
    external:
      name: myglobalnetwork
# docker-compose-other.yml
version: '3.9'
services:
  other_app:
    image: busybox
    command: ping main_app
    networks:
      - default
      - global
networks:
  global:
    external:
      name: myglobalnetwork

然后我们可以启动主要的 docker-compose 项目:

✖2 ❯ docker-compose -f docker-compose.yml up
Starting stackoverflow_db_app_1 ... done
Starting stackoverflow_main_app_1 ... done
Attaching to stackoverflow_db_app_1, stackoverflow_main_app_1
db_app_1    | 1:C 18 Mar 2021 00:00:41.103 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
db_app_1    | 1:C 18 Mar 2021 00:00:41.103 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=1, just started
db_app_1    | 1:C 18 Mar 2021 00:00:41.103 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
main_app_1  | PING main_app (172.28.0.2): 56 data bytes
main_app_1  | 64 bytes from 172.28.0.2: seq=0 ttl=64 time=0.028 ms
db_app_1    | 1:M 18 Mar 2021 00:00:41.104 * monotonic clock: POSIX clock_gettime
<snip some redis logs>
db_app_1    | 1:M 18 Mar 2021 00:00:41.105 * Ready to accept connections
main_app_1  | 64 bytes from 172.28.0.2: seq=1 ttl=64 time=0.067 ms
main_app_1  | 64 bytes from 172.28.0.2: seq=2 ttl=64 time=0.059 ms
main_app_1  | 64 bytes from 172.28.0.2: seq=3 ttl=64 time=0.120 ms

这个可以 ping 自己,这很棒,但没有那么令人兴奋或不同。

真正的魔力是当我们启动第二个时,它会尝试引用第一个。

❯ docker-compose -f docker-compose-other.yml up
Starting other_other_app_1 ... done
Attaching to other_other_app_1
other_app_1  | PING main_app (172.28.0.2): 56 data bytes
other_app_1  | 64 bytes from 172.28.0.2: seq=0 ttl=64 time=0.112 ms
other_app_1  | 64 bytes from 172.28.0.2: seq=1 ttl=64 time=0.112 ms

这就是我们相互学习 docker 容器的方式!如果您有兴趣,可以在这里进一步阅读:https://docs.docker.com/compose/networking/

【讨论】:

  • 谢谢你,泰勒。但是,还有另一种方法可以让 app2 docker-compose 的服务对 app1 docker-compose 可用,而无需创建全局网络?我无法理解的是为什么即使请求是使用 : 发出的,我也无法向该容器发出请求,所以请求出去,然后返回进入机器并路由是正确的,两个组合之间没有网络,因为请求来自外部,就像其他机器发出请求或当前机器执行请求一样。我是对的?
  • hrm 好的,这很棘手。让我们尝试一些东西 - 在 app1 中,你能运行 dig name.domain.examplenslookup name.domain.example 吗?在您的主机上执行相同的操作。它们是否解析到相同的 IP 地址? - 尝试使用host.docker.internal:4202 看看是否有效
  • 是的,这行得通。我也已经尝试过 ping 并且 IP 10.X.X.X 显示给我。
猜你喜欢
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
相关资源
最近更新 更多