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

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

  • ~/front/docker-compose.yml
  • ~/api/docker-compose.yml

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

我知道--default-gateway选项可以使用docker run为单个容器设置,以便可以为该容器分配特定的IP地址,但似乎在使用docker-compose时这个选项不可用。

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

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

  • 我可以使用docker-compose将一个固定的IP地址归属于特定的容器吗?

但最终我所追求的是:

  • 两个不同的docker-compose项目如何相互通信?
363853 次浏览

您只需要确保希望相互通信的容器位于同一网络上。网络是一流的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

注意:你的应用程序的网络是根据“项目名”来命名的,而“项目名”是基于它所在目录的名称,在这种情况下,前缀front_被添加了

然后,它们可以使用服务名相互通信。从front你可以做ping api,反之亦然。

我将确保所有容器都__abc0d到同一个网络,通过同时将它们组合在一起,使用:

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编写指南:使用现有网络(见底部)

之前的帖子信息是正确的,但是没有详细说明如何链接容器,应该连接为“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

上面假设你已经将version设置为3.5(或更高,如果他们在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

对于使用另一个docker-compose网络,你只需要做这些(在docker-compose之间共享网络):

  1. 通过up -d运行第一个docker-compose项目
  2. 找到第一个docker的网络名称-通过:docker network ls(它包含根目录项目的名称)
  3. 然后在第二个docker-compose文件中使用下面这个结构的名称。

第二个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中运行应用程序时自动创建的。例如,一个API网络将被创建为ner_default,评分API网络将被命名为scoring default。此解决方案适用于版本:'3'。

在上面的场景中,我的评分API想要与另一个API通信,然后我将添加以下行。这意味着每当我为ner API创建容器时,它会自动添加到scoring_default网络。

networks:
default:
external:
name: scoring_default

尼珥/ docker-compose.yml

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


networks:
default:
external:
name: scoring_default

得分/ docker-compose.yml

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

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

Docker检查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

< p >的例子 App1 -在服务行中创建的new-network,在底部标记为external: true App2 -表示app1在运行时创建的“新网络”,在底部标记为external: true,并在配置中设置为连接,app1在此网络中的IP

有了这个,你们就能互相交谈了

*这种方式只是局部测试的焦点,为了不做过于复杂的配置 **我知道这是非常“补丁的方式”,但对我来说是有效的,我认为是如此简单,其他人可以利用这个

你可以在所有包含COMPOSE_PROJECT_NAME=somename的项目中添加一个.env文件。

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

注意:您将得到从其他项目创建的“孤立”容器的警告。

如果你是

  • 尝试在不同的docker-compose项目不想使用同一个网络的两个容器之间进行通信(因为我们假设它们在同一个端口上有PostgreSQL或Redis容器,而你不希望改变这些端口,也不希望在同一个网络上使用它们)
  • 在本地开发,并想模仿两个docker组合项目之间的通信
  • 在本地主机上运行两个docker-compose项目
  • 开发Django应用程序或Django Rest Framework (drf) API,并在容器中运行应用程序
  • 在尝试在两个容器之间通信时获得Connection refused

你想要

  • 容器api_aapi_b通信(反之亦然),但没有相同的“docker网络”。

(下面的例子)

你可以使用第二个容器的“host”作为你的计算机的IP和端口,从Docker容器内部映射。你可以用这个脚本获取你的计算机的IP地址(从:使用Python's stdlib查找本地IP地址):

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 < / p >

第二种是船坞结构。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 < / p > 并且尝试从容器api_a连接到api_b,那么api_b容器的URL将是: http://<get_ip_from_script_above>:8001/ < / p >

如果你正在使用超过两个(三个或更多)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 up时,Docker将创建一个默认网络,并为mongo和server分配服务名作为主机名。

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

docker exec -it server bash

现在你可以使用Dockers内部网络(默认端口为27017)来ping mongo容器:

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

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

我有一个类似的例子,我在一个有覆盖网络的docker群上使用独立的docker-compose文件,我所要做的就是改变网络参数,如下所示:

第一个docker-compose.yaml

version: '3.9'
.
.
.


networks:
net:
driver: overlay
attachable: true
docker-compose -p app up
由于我已经使用-p将应用程序名称指定为app,因此初始网络将是app_net。 现在,为了运行另一个docker-compose与多个使用同一网络的服务,你需要这样设置:

第二个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:确保检查docker-compose版本是很重要的。

这么多答案!

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

示例: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都放在这个网络中, 你可以用Docker网络创建网络名称创建networkrok,

或者你可以简单地把网络声明放在docker-compose文件的网络选项中,当你运行docker-compose (docker-compose up)时,网络就会自动创建。

在两个docker-compose文件中放入下面的行

networks:
net-for-alpine:
name: test-db-net
注意:net-for-alpine是网络的内部名称,它将在docker-compose文件中使用,可以是不同的, Test-db-net 是网络的外部名称,在两个docker-compose文件中必须相同。

假设我们有docker-compose.db。Yml和docker-compose.alpine.yml

docker-compose.apline。Yml是:

version: '3.8'


services:


alpine:
image: alpine:3.14
container_name: alpine
networks:
- net-for-alpine
  

# these two command keeps apline container running
stdin_open: true # docker run -i
tty: true # docker run -t






networks:
net-for-alpine:
name: test-db-net

docker-compose.db。Yml是:

version: '3.8'


services:


db:
image: postgres:13.4-alpine
container_name: psql
networks:
- net-for-db
  

networks:
net-for-db:
name: test-db-net

要测试网络,请进入alpine容器

docker exec -it alpine sh
      

然后使用以下命令可以检查网络

# if it returns 0 or see nothing as a result, network is established
nc -z psql (container name)

ping pgsql
  1. < p > foldername / docker-compose。yml: 1日

    < p >版本:' 2 ' 服务: some-contr: container_name: [] 构建:。 ... 网络: ——somenet 港口: ——“8080:8080" 公开: 打开容器的8080端口 ——“8080”; 环境: 端口:8080 tty:真 网络: boomnet: 司机:桥 ipam: 配置: —子网:172.22.0.0/24 网关:172.22.0.1 < / p >
  2. < p > docker-compose。yml: 2

    < p >版本:' 2 ' 服务: pushapiserver: container_name (container_name): 构建:。 命令:"tail -f /dev/null" 卷: ——。/:/ (work_dir) Working_dir: /[工作目录] 图片:【图片名称】 港口: ——“8066:8066" 环境: 端口:8066 tty:真 网络: ——foldername_somenet 网络: foldername_somenet: 外部:真正的< / p >
现在你可以对另一个服务(b/w diff容器)进行api调用,如: 从文件中的一些代码中调用第一个docker的http://pushapiserver:8066/send_push -compose.yml

我正在运行多个相同的docker-compose。Yml文件放在不同的目录下,使用.env文件做一些细微的区别。并使用Nginx Proxy Manage与其他服务通信。这是我的文件:

确保已创建公共网络

docker network create nginx-proxy-man

/domain1.com/docker-compose.yml, /domain2.com/docker-compose.yml,…

version: "3.9"


services:
webserver:
build:
context: ./bin/${PHPVERSION}
container_name: "${COMPOSE_PROJECT_NAME}-${PHPVERSION}"
...
networks:
- default    # network outside
- internal   # network internal
database:
build:
context: "./bin/${DATABASE}"
container_name: "${COMPOSE_PROJECT_NAME}-${DATABASE}"
...
networks:
- internal   # network internal




networks:
default:
external: true
name: nginx-proxy-man
internal:
internal: true

.env文件只需更改COMPOSE_PROJECT_NAME

COMPOSE_PROJECT_NAME=domain1_com
.
.
.
PHPVERSION=php56


DATABASE=mysql57

网络服务器。container_name: domain1_com-php56 -将加入默认网络(名称:Nginx - Proxy -man),之前为Nginx代理管理器创建,以便从外部访问。

备注:container_name在同一网络中是唯一的。

数据库。Container_name: domain1_com-mysql57—更容易区分

在同样的docker-compose中。Yml,由于相同的网络domain1_com_internal,服务将通过服务名称相互连接。为了更加安全,请使用选项internal: true设置此网络

注意,如果您没有显式地为每个服务指定网络,而只是为两个docker-compose使用一个公共的外部网络。嗯,那么domain1_com很可能会使用domain2_com的数据库。