多个 docker-compose 项目之间的通信

Communication between multiple docker-compose projects

我在两个不同的文件夹中有两个单独的 docker-compose.yml 文件:

如何确保 front 中的容器可以向 api 中的容器发送请求?

我知道 --default-gateway 选项可以使用 docker run 为单个容器设置,这样就可以为这个容器分配一个特定的 IP 地址,但是这个选项似乎不可用使用 docker-compose.

目前我最终做了一个 docker inspect my_api_container_id 并查看输出中的网关。它有效,但问题是这个 IP 是随机分配的,所以我不能依赖它。

这个问题的另一种形式可能是:

但最终我要照顾的是:

你只需要确保你想互相交谈的容器在同一个网络上。网络是第一个 class docker 构造,并不特定于组合。

# front/docker-compose.yml
version: '2'
services:
  front:
    ...
    networks:
      - some-net
networks:
  some-net:
    driver: bridge

...

# api/docker-compose.yml
version: '2'
services:
  api:
    ...
    networks:
      - front_some-net
networks:
  front_some-net:
    external: true

Note: Your app’s network is given a name based on the “project name”, which is based on the name of the directory it lives in, in this case a prefix front_ was added

然后他们可以使用服务名称相互交谈。从 front 开始,您可以 ping api 反之亦然。

我会确保所有容器都docker-compose连接到同一个网络,方法是同时将它们组合在一起,使用:

docker compose --file ~/front/docker-compose.yml --file ~/api/docker-compose.yml up -d

只是对@johnharris85 的精彩回答的一点补充, 当您 运行 撰写 docker 文件时,将创建一个“default”网络 所以你可以将它作为外部网络添加到另一个撰写文件中:

# front/docker-compose.yml 
version: '2' 
  services:   
    front_service:
    ...

...

# api/docker-compose.yml
version: '2'
services:
  api_service:
    ...
    networks:
      - front_default
networks:
  front_default:
    external: true

对我来说,这种方法更合适,因为我不拥有第一个 docker-compose 文件,但想与它通信。

来自 api 的所有容器都可以使用以下配置加入 front 默认 网络:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

请参阅 docker 撰写指南:using a pre existing network(请参阅底部)

之前的帖子信息是正确的,但是没有详细说明如何link容器,应该连接为"external_links"。

希望这个例子让你更清楚:

  • 假设你有 app1/docker-compose.yml,有两个服务(svc11 和 svc12),app2/docker-compose.yml 还有两个服务(svc21 和 svc22),假设你需要交叉连接:

  • svc11 需要连接到 svc22 的容器

  • svc21 需要连接到 svc11 的容器。

所以配置应该是这样的:

这是app1/docker-compose.yml:


version: '2'
services:
    svc11:
        container_name: container11
        [..]
        networks:
            - default # this network
            - app2_default # external network
        external_links:
            - container22:container22
        [..]
    svc12:
       container_name: container12
       [..]

networks:
    default: # this network (app1)
        driver: bridge
    app2_default: # external network (app2)
        external: true

这是app2/docker-compose.yml:


version: '2'
services:
    svc21:
        container_name: container21
        [..]
        networks:
            - default # this network (app2)
            - app1_default # external network (app1)
        external_links:
            - container11:container11
        [..]
    svc22:
       container_name: container22
       [..]

networks:
    default: # this network (app2)
        driver: bridge
    app1_default: # external network (app1)
        external: true

更新:自撰写文件版本 3.5 起:

现在有效:

version: "3.5"
services:
  proxy:
    image: hello-world
    ports:
      - "80:80"
    networks:
      - proxynet

networks:
  proxynet:
    name: custom_network

docker-compose up -d 将加入名为 'custom_network' 的网络。不存在则创建!

root@ubuntu-s-1vcpu-1gb-tor1-01:~# docker-compose up -d
Creating network "custom_network" with the default driver
Creating root_proxy_1 ... done

现在,您可以这样做:

version: "2"
services:
  web:
    image: hello-world
    networks:
      - my-proxy-net
networks:
  my-proxy-net:
    external:
      name: custom_network

这将创建一个将在外部网络上的容器。

我在文档中找不到任何参考,但它有效!

自 Compose 1.18(规范 3.5)以来,您可以使用自己的自定义名称为您需要的所有 Compose YAML 文件覆盖默认网络。只需将以下内容附加到它们即可:

networks:
  default:
    name: my-app

The above assumes you have version set to 3.5 (or above if they don't deprecate it in 4+).

其他答案都指向相同;这是一个简化的摘要。

version: '2'
services:
  bot:
    build: .
    volumes:
      - '.:/home/node'
      - /home/node/node_modules
    networks:
      - my-rede
    mem_limit: 100m
    memswap_limit: 100m
    cpu_quota: 25000
    container_name: 236948199393329152_585042339404185600_bot
    command: node index.js
    environment:
      NODE_ENV: production
networks:
  my-rede:
    external:
      name: name_rede_externa

For using another docker-compose network you just do these(to share networks between docker-compose):

  1. Run the first docker-compose project by up -d
  2. Find the network name of the first docker-compose by: docker network ls(It contains the name of the root directory project)
  3. Then use that name by this structure at below in the second docker-compose file.

秒docker-compose.yml

version: '3'
services:
  service-on-second-compose:  # Define any names that you want.
    .
    .
    .
    networks:
      - <put it here(the network name that comes from "docker network ls")>

networks:
  - <put it here(the network name that comes from "docker network ls")>:
    external: true

更新:从 docker-compose 文件版本 3.5 开始:

我遇到了类似的问题,我通过在我的 docker-compose.yml 项目之一中添加一个小改动解决了这个问题。

例如,我们有两个API的scoringnerScoring API 需要发送请求到 ner API 处理输入请求。为了做到这一点,他们应该共享同一个网络。

注意:每个容器都有自己的网络,该网络是在运行 docker 内的应用程序时自动创建的。例如 ner API 网络将被创建为 ner_default 并且评分 API 网络将被命名为 scoring default。此解决方案适用于版本:“3”。

和上面的场景一样,我的得分API想和nerAPI交流,那么我将添加以下几行。这意味着每当我为 ner API 创建容器时,它就会自动添加到 scoring_default 网络。

networks:
  default:
      external:
        name: scoring_default

ner/docker-compose.yml

version: '3'
services:
  ner:
    container_name: "ner_api"
    build: .
    ...

networks:
  default:
      external:
        name: scoring_default

scoring/docker-compose.yml

version: '3'
services:
  api:
    build: .
    ...

我们可以看到上面的容器现在是如何成为同一网络的一部分的 scoring_default 使用命令:

docker inspect scoring_default

{
    "Name": "scoring_default",
        ....
    "Containers": {
    "14a6...28bf": {
        "Name": "ner_api",
        "EndpointID": "83b7...d6291",
        "MacAddress": "0....",
        "IPv4Address": "0.0....",
        "IPv6Address": ""
    },
    "7b32...90d1": {
        "Name": "scoring_api",
        "EndpointID": "311...280d",
        "MacAddress": "0.....3",
        "IPv4Address": "1...0",
        "IPv6Address": ""
    },
    ...
}

另一种选择是 运行 使用 'docker-compose' 检查与模块相关的 ip,然后将第二个模块与前面的网络连接起来,并指向内部 ip

例子 app1 - 在服务线路中创建的新网络,标记为外部:底部为真 app2 - 表示app1在up时创建的"new-network",在底部标记为external: true,并在config中设置连接,app1在本网的ip。

有了这个,你们应该可以互相交谈了

*此方式仅针对本地测试,以免配置过于复杂 ** 我知道非常 'patch way' 但对我有用,我认为这很简单,其他人可以利用这个

您可以在包含 COMPOSE_PROJECT_NAME=somename.

的所有项目中添加 .env 文件

COMPOSE_PROJECT_NAME 覆盖用于命名资源的前缀,因此您的所有项目都将使用 somename_default 作为它们的网络,从而使服务可以像在同一个环境中一样相互通信项目。

注意:对于从其他项目创建的 "orphaned" 个容器,您会收到警告。

如果你是

  • 尝试在来自不同docker-compose 项目的两个容器之间进行通信并且不想使用相同的网络(因为假设他们将在同一端口上安装 PostgreSQL 或 Redis 容器,而您宁愿不更改这些端口,也不要在同一网络上使用它们)
  • 在本地开发,想模仿两个docker组合项目之间的通信
  • 运行 两个 docker-在本地主机上编写项目
  • 特别开发 Django 应用程序或 Django Rest Framework (drf) API 和 运行 应用程序在容器内的某些暴露端口
  • 在尝试在两个容器之间进行通信时得到 Connection refused

你想要

  • 容器 api_aapi_b 通信(反之亦然),但没有相同的 "docker network"

(示例如下)

您可以使用第二个容器的 "host" 作为计算机的 IP 和从 Docker 容器内部映射的端口。您可以使用此脚本获取计算机的 IP(来自:Finding local IP addresses using Python's stdlib):

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

示例:

project_api_a/docker-compose.yml:

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_a
    image: api_a:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

api_a 容器中你是 运行 Django 应用程序: manage.py runserver 0.0.0.0:8000

和第二个 docker-compose.yml 来自其他项目:

project_api_b/docker-compose-yml :

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_b
    image: api_b:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

api_b 容器中你是 运行 Django 应用程序: manage.py runserver 0.0.0.0:8001

并尝试从容器 api_a 连接到 api_b 然后 api_b 容器的 URL 将是: http://<get_ip_from_script_above>:8001/

如果您使用超过两个(三个或更多)docker-compose 项目并且很难为所有这些项目提供公共网络 - 这是很好的解决方法和解决方案

回答 Docker 撰写“3”及以上

默认情况下Docker Compose 使用桥接网络来提供容器间通信。阅读本文了解有关容器间网络的更多信息。

对您来说重要的是,默认情况下 Docker Compose 创建的主机名等于 docker-compose.yml 文件中的服务名称。考虑以下 docker-compose.yml:

version: '3.9'
services:
  server:
    image: node:16.9.0
    container_name: server
    tty: true
    stdin_open: true
    depends_on:
       - mongo
    command: bash

  mongo:
    image: mongo
    environment:
      MONGO_INITDB_DATABASE: my-database

当您 运行 docker-compose 时,Docker 将创建一个默认网络并将服务名称分配为 mongo 和服务器的主机名。

您现在可以通过以下方式访问后端容器:

docker exec -it server bash

现在您可以使用 Docker 的内部网络(在这种情况下默认端口 27017)ping mongo 容器:

curl -v http://mongo:27017/my-database

就是这样。这同样适用于您的设置。

我有一个类似的例子,我正在处理单独的 docker-compose 文件,这些文件在具有覆盖网络的 docker 群上工作,我所要做的就是改变 networks 参数如下:

docker-compose.yaml

version: '3.9'
.
.
.

networks:
  net:
    driver: overlay
    attachable: true
docker-compose -p app up

由于我已使用 -p 将应用名称指定为 app,因此初始网络将为 app_net。 现在,为了 运行 另一个 docker- 与将使用同一网络的多个服务组合,您需要将它们设置为:

docker-compose.yaml

version: '3.9'
.
.
.
networks:
  net-ref:
    external: true
    name: app_net
docker stack deploy -c docker-compose.yml mystack

无论您为堆栈指定什么名称,网络都不会受到影响,并且将始终引用名为 app_net 的现有外部网络。

PS: It's important to make sure to check your docker-compose version.

这么多答案!

首先,避免在服务和网络等实体名称中使用连字符。它们会导致名称解析问题。

示例:my-api 将不起作用。 myapiapi 都可以。

对我有用的是:

# api/docker-compose.yml
version: '3'

services:
  api:
    container_name: api
    ...
    ports:
      - 8081:8080
    networks:
      - mynetwork

networks:
  mynetwork:
    name: mynetwork

# front/docker-compose.yml
version: '3'

services:
  front:
    container_name: front
    ...
    ports:
      - 81:80
    networks:
      - mynetwork

networks:
  mynetwork:
    name: mynetwork

注意:我添加了端口以显示服务如何相互访问,以及如何从主机访问它们。

重要提示:如果您没有指定网络 namedocker-compose 会为您制作一个。它使用 docker_compose.yml 文件所在文件夹的名称。在本例中:api_mynetworkfront_mynetwork。这将阻止容器之间的通信,因为它们将在不同的网络上使用非常相似的名称。

请注意,网络在两个文件中的定义完全相同,因此您可以先启动任何一个服务,它都会起作用。无需指定哪一个是外部的,docker-compose 会为您管理。

来自主持人

您可以使用 docker-compose.yml 中定义的 已发布端口 访问任一容器。

您可以访问 Front 容器:curl http://localhost:81

您可以访问 API 容器:curl http://localhost:8081

来自 API 容器

您可以使用 原始端口 访问 Front 容器,而不是您在 docker-compose.yml.

中发布的端口

示例:curl http://front:80

来自前端容器

您可以使用 原始端口 访问 API 容器,而不是您在 docker-compose.yml 中发布的端口。

示例:curl http://api:8080

大家已经解释的很好了,所以我会添加必要的代码,简单的解释一下。

使用 docker-compose 之外创建的网络(“外部”网络) docker-compose 版本 3.5+.

Further explanation can be found here.

第一个 docker-compose.yml 文件应定义名称为 giveItANamePlease 的网络,如下所示。

networks:
  my-network:
    name: giveItANamePlease
    driver: bridge

第一个docker-compose.yml文件的服务可以使用如下网络:

networks:
  - my-network

second docker-compose 文件中,我们需要使用我们在第一个 docker-compose 文件中使用的网络名称来代理网络,这在这种情况是 giveItANamePlease:

networks:
  my-proxy-net:
    external:
      name: giveItANamePlease

现在您可以在第二个 docker-compose.yml 文件的服务中使用 my-proxy-net,如下所示。

networks:
  - my-proxy-net