为什么可以';我不能通过主机将一个docker容器与另一个容器卷曲

为什么可以';我不能通过主机将一个docker容器与另一个容器卷曲,docker,Docker,我真的不明白这里发生了什么。我只想使用主机的公共ip在发布的端口上,通过主机执行从一个docker容器内部到另一个docker容器的http请求 这是我的设置。我有我的开发机器。我有一台docker主机和两个容器。CONT_A侦听并发布端口3000上的web服务 DEV-MACHINE HOST (Public IP = 111.222.333.444) CONT_A (Publish 3000) CONT_B 在我的开发机器上(完全不同的机器) 我可以毫无问题地卷曲 curl h

我真的不明白这里发生了什么。我只想使用主机的公共ip在发布的端口上,通过主机执行从一个docker容器内部到另一个docker容器的http请求

这是我的设置。我有我的开发机器。我有一台docker主机和两个容器。CONT_A侦听并发布端口3000上的web服务

DEV-MACHINE

HOST (Public IP = 111.222.333.444)
  CONT_A (Publish 3000)
  CONT_B

在我的开发机器上(完全不同的机器)

我可以毫无问题地卷曲

curl http://111.222.333.444:3000 --> OK
当我使用SSH连接到主机时

我可以毫无问题地卷曲

curl http://111.222.333.444:3000 --> OK
当我在CONT_B内部执行时

不可能,只是超时。虽然平很好

docker exec -it CONT_B bash
$ curl http://111.222.333.444:3000 --> TIMEOUT
$ ping 111.222.333.444 --> OK
为什么?


Ubuntu 16.04,Docker 1.12.3(默认网络设置)

我知道这并不是严格地回答这个问题,但有一种更像Docker的方法来解决你的问题。我会完全忘记发布用于集装箱间通信的端口。而是使用docker swarm创建覆盖网络。您可以找到完整的指南,但本质上您可以执行以下操作:

//create network    
docker network create --driver overlay --subnet=10.0.9.0/24 my-net
//Start Container A
docker run -d --name=A --network=my-net producer:latest
//Start Container B
docker run -d --name=B --network=my-net consumer:latest

//Magic has occured
docker exec -it B /bin/bash
> curl A:3000 //MIND BLOWN!
然后在容器中,您可以只卷曲主机名A,它将为您解决问题(即使您开始进行缩放等)

如果您不喜欢使用Docker swarm,也可以使用Docker遗留链接:

docker run -d --name B --link A:A consumer:latest
它将链接容器中的任何公开(未发布)端口


最后,如果您开始转向生产…完全忘记链接和覆盖网络…使用Kubernetes:-)初始设置有点困难,但它们引入了一系列概念和工具,使链接和缩放容器集群变得更容易!但这只是我个人的观点。

我有一个类似的问题,我在一个容器中安装了一个nginx服务器(我们称之为web),其中包含多个服务器块,在另一个容器中安装了cron(我们称之为cron)。我使用docker编写。我想不时使用curl from cron to web在一个应用程序上执行一些php脚本。它应该如下所示:

curl http://app1.example.com/some_maintance.php
但过了一段时间,我总是找不到主人

第一个解决方案是更新cron容器中的/etc/hosts,并添加:

1.2.3.4 app1.example.com
其中1.2.3.4是web容器的ip,它起了作用——但这是一种黑客行为——据我所知,这种手动更新是不受鼓励的。您应该在docker compose中使用
extra_hosts
,它需要显式的ip地址而不是容器名称来指定ip地址

我尝试使用自定义网络解决方案,正如我所看到的,这是正确的处理方法,但我在这里从未成功过。如果我学会了怎么做,我保证会更新这个答案

最后,我使用curl功能指定服务器的IP地址,并在单独的参数中将域名作为头传递:

curl -H'Host: app1.example.com' web/some_maintance.php
不是很漂亮,但确实有用


(这里web是我的nginx容器的名称)

通过使用
--network host
参数运行容器B,您可以使用localhost访问容器A,无需公共ip

> docker run -d --name containerB --network host yourimagename:version
在使用上述命令运行容器B之后,您可以像这样从容器B中尝试curl容器A

> docker exec -it containerB /bin/bash
> curl http://localhost:3000

我认为这可能是因为Docker如何使用IPTables和桥接网络处理网络。我必须查一下,但我猜您提供的IP地址可能是从主机上看到的IP地址,而不是docker网络中分配的“内部IP”。ping可能解析的原因是它解析到docker主机(而不是容器)。但是docker实现这一点的方法是不在容器A中发布端口,而是创建一个覆盖网络。@RikNauta我使用的IP地址是公共主机IP。当然,除非它与内部docker网络发生冲突,否则应该始终正确解决。这是一个
104….
ip地址。应该可以。docker运行一个userland代理进程来侦听主机并将tcp连接转发到容器中。Docker 1.11中也有同样的功能吗?您是否在docker守护进程中将
userland proxy
设置为false?@Matt我还没有测试docker 1.11,我不确定userland proxy。我没有碰过它,所以我假设它是默认的。有趣的是,当我在谷歌上搜索“userland proxy”时,我发现这一点非常确定,在容器不能与自己主机上的暴露端口通信的情况下,总是这样。如果iptables、nat/mangle规则或docker代理未配置为支持这一开箱即用,则不会感到惊讶。由于您可以直接从一个容器到另一个容器进行对话,因此对我来说,这从来都不是一个值得调试的问题。当您在一台主机上时,它甚至不需要是一个覆盖网络,默认的网桥驱动程序将在一个文件中工作。