2 个 docker 容器可以(或应该)通过 localhost 相互交互吗?
Posted
技术标签:
【中文标题】2 个 docker 容器可以(或应该)通过 localhost 相互交互吗?【英文标题】:Can (or should) 2 docker containers interact with each other via localhost? 【发布时间】:2018-01-15 01:23:54 【问题描述】:我们正在对我们的微服务应用进行 docker 化,但我遇到了一些发现问题。
应用配置如下:
当服务以“非本地”模式启动时,它使用 Consul 作为其发现注册表。 当服务以“本地”模式启动时,它会自动为每个服务绑定一个地址(例如,tcp://localhost:61001、tcp://localhost:61002 等。硬编码地址)
在对应用程序进行 docker 化后(目前仅适用于本地模式),每个服务都是一个容器(使用 docker-compose 编排的 Docker 映像。如果重要的话,还可以使用 docker-machine) 但是一个服务不能与另一个服务交互,因为它们不在同一台机器上,而且 tcp://localhost:61001 显然不起作用。
使用 docker-compose 和 links 并将 localhost 指定为别名 (service:localhost) 不起作用。有没有办法让 2 个容器“共享”同一个本地主机?
如果不是,解决此问题的最佳方法是什么? 我考虑过为每个服务使用特定的主机名,然后在 docker-compose 的链接部分指定主机名。 (但我怀疑这是优雅的解决方案) 或者也许使用 dockerized 版本的 Consul 并与之集成?
这篇文章:How to share localhost between two different Docker containers? 提供了一些关于为什么 localhost 不应该被搞乱的见解 - 但我仍然对这里的正确方法感到很困惑。
谢谢!
【问题讨论】:
绑定到 0.0.0.0 而不是 localhost,然后通过上述链接共享。您不需要手动指定主机名,默认情况下它是容器名称。 【参考方案1】:在生产环境中,切勿单独使用 docker 或 docker compose。使用编排器(rancher、docker swarm、k8s、...)并在那里部署您的堆栈。 Orchestrator 将处理网络问题。您的容器可以相互链接,因此您可以通过名称直接访问它们(不要太在意ip)。
在本地主机上,使用 docker compose 启动容器并使用链接。不要使用本地端口,而是使用链接的名称。 (如果您的容器 A 需要访问端口 1234 上的容器 B,则使用名称 BBBB 链接到 A 的链接 B 并使用 tcp://BBBB:1234 从 A 访问容器)
如果您真的想将端口绑定到您的本地主机并使用它,请通过您的主机 IP 访问端口,而不是本地主机。
【讨论】:
为什么不应该在生产环境中使用 docker-compose? 如果一个容器崩溃了,不会自动重启。如果一个容器重新启动,您必须重新启动所有容器以重新同步链接(其他容器保留旧 ip)。你只能使用一台主机,规模很难,...【参考方案2】:但是一个服务不能与另一个服务交互,因为它们不在同一台机器上,而且 tcp://localhost:61001 显然不起作用。
实际上,他们可以。你说得对,tcp://localhost:61001
不起作用,因为在容器中使用localhost
将引用容器本身,类似于默认情况下localhost
在任何系统上的工作方式。这意味着您的服务不能共享同一个主机。如果您愿意,您可以为两种服务使用一个容器,尽管这确实不是最好的设计,因为它违背了 Docker Compose 的主要目的之一。
理想的方法是使用 docker-compose 链接,您引用的指南显示了如何定义它们,但要真正使用它们,您需要在 URL 中使用链接容器的名称,就好像链接容器的名称在原始容器的/etc/hosts
中定义了一个 IP 映射(实际上并非如此,但只是为了让您明白)。如果您想将其更改为与链接容器的名称不同的名称,您可以使用链接别名,在您引用的同一指南中对此进行了说明。
例如,docker-compose.yml
文件如下:
a:
expose:
- "9999"
b:
links:
- a
通过a
监听0.0.0.0:9999
,b
可以通过从b
向tcp://a:9999
发出请求来与a
交互。也可以进入b
并运行
ping a
这会将 ping 请求从 b
容器发送到 a
容器。
因此,总而言之,尝试将请求 URL 中的 localhost
替换为链接容器的文字名称(或链接别名,如果链接是使用别名定义的)。这意味着
tcp://<container_name>:61001
应该工作而不是
tcp://localhost:61001
只需确保在 docker-compose.yml
中定义链接即可。
希望对你有帮助
【讨论】:
【参考方案3】:如果现在无法更改硬编码地址,也许您可以修改容器的启动脚本,将每个本地容器中的转发端口转发到其他机器中所需的服务。
但这会带来一些复杂性,因为您必须在每个容器中设置 ssh,并管理相应的密钥。
想一想,如果加密不是问题,ssh 就没有必要了。使用socat 或redir 将是probably be enough。
socat TCP4-LISTEN:61001,fork TCP4:othercontainer:61001
【讨论】:
以上是关于2 个 docker 容器可以(或应该)通过 localhost 相互交互吗?的主要内容,如果未能解决你的问题,请参考以下文章