即使正在解析 DNS,也无法连接到同一主机中的容器

问题描述

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

Diagram1

在“机器 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 for app2

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

连接不起作用。这很奇怪,因为其他连接有效,例如:

Diagram2

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

Diagram3

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

Diagram4

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

Diagram5

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

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

name.domain.example

我尝试将 app1 放在网络“主机”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')) 或 docker-compose--network=host 上,我可以访问 app2 的容器。但是,这对我的情况没有用,因为我需要来自组合堆栈的其他服务,此外,随着服务的增加和相互依赖程度的提高,这最终会变成蜘蛛网。

解决方法

这里的技巧是 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/命名空间网络并驻留在主机的主命名空间中。从这里,他们可以看到您通常可以看到的一切。

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

首先,我们在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/

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...