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:9999b 可以通过从btcp://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 相互交互吗?的主要内容,如果未能解决你的问题,请参考以下文章

Docker网络

docker 的container模式

Docker 网络

Docker 网络

我可以通过内部网址到达docker启动的服务吗?

docker学习-bridge网络