2 docker 容器可以(或应该)通过本地主机相互交互吗?

Can (or should) 2 docker containers interact with each other via localhost?

我们正在 docker 化我们的微服务应用程序,我 运行 遇到了一些发现问题。

应用配置如下:

当服务以 'non-local' 模式启动时,它使用 Consul 作为其 Discovery 注册表。 当一个服务以'local'模式启动时,它会自动为每个服务绑定一个地址(例如,tcp://localhost:61001,tcp://localhost:61002 等等。硬编码地址)

在 docker 化应用程序(目前仅适用于本地模式)后,每个服务都是一个容器(Docker 图像使用 docker-compose 编排。并且使用 docker-机器,如果重要的话) 但是一个服务不能与另一个服务交互,因为它们不在同一台机器上,tcp://localhost:61001 显然不起作用。

将 docker-compose 与 links 结合使用并将本地主机指定为别名 (service:localhost) 无效。有没有办法让 2 个容器 "share" 同一个本地主机?

如果不是,解决这个问题的最佳方法是什么? 我考虑过为每个服务使用特定的主机名,然后在 docker-compose 的链接部分指定主机名。 (但我怀疑这是优雅的解决方案) 或者可以使用 docker 化版本的 Consul 并与之集成?

这个 post:How to share localhost between two different Docker containers? 提供了一些关于为什么不应该乱用 localhost 的见解 - 但我仍然很困惑这里的正确方法是什么。

谢谢!

在生产环境中,切勿单独使用 docker 或 docker 组合。使用编排器(rancher,docker swarm,k8s,...)并在那里部署你的堆栈。 Orchestrator 将处理网络问题。你的容器可以link彼此,所以你可以通过名称直接访问它们(不要太在意ip)。

在本地主机上,使用 docker compose 启动容器并使用 link。不要使用本地端口而是 link 的名称。 (如果您的容器 A 需要访问端口 1234 上的容器 B,则执行 link B linked 到名称为 BBBB 的 A 并使用 tcp://BBBB:1234 从 A 访问容器)

如果您真的想将端口绑定到您的本地主机并使用它,请通过您的主机 IP 访问端口,而不是本地主机。

But one service can not interact with another service since they are not on the same machine and tcp://localhost:61001 will obviously not work.

事实上,他们可以。你是对的,tcp://localhost:61001 不会工作,因为在容器中使用 localhost 将引用容器本身,类似于 localhost 默认情况下在任何系统上的工作方式。这意味着您的服务不能共享同一主机。如果需要,您可以为两种服务使用一个容器,尽管这确实不是最佳设计,因为它违背了 Docker Compose 的主要目的之一。

理想的方法是使用 docker-compose links,您引用的指南显示了如何定义它们,但实际上 使用 他们需要在 URLs 中使用 linked 容器的名称,就好像 linked 容器的名称在原始容器的 /etc/hosts 中定义了 IP 映射(不是那个它实际上确实如此,但只是让你明白了)。如果您想将其更改为不同于 linked 容器的名称,您可以使用 link 别名,在您引用的同一指南中对此进行了解释。

例如,使用这样的 docker-compose.yml 文件:

a:
  expose:
    - "9999"
b:
  links:
    - a

通过 a 监听 0.0.0.0:9999b 可以通过从 btcp://a:9999 发出请求来与 a 交互。也可以将 shell 转换为 b 和 运行

ping a

这将从 b 容器向 a 容器发送 ping 请求。

所以总而言之,尝试将请求 URL 中的 localhost 替换为 linked 容器的文字名称(或 link 别名,如果 link 是用别名定义的)。这意味着

tcp://<container_name>:61001

应该可以代替

tcp://localhost:61001

只需确保在 docker-compose.yml 中定义 link。

希望对您有所帮助

如果现在不能更改硬编码地址,也许您可​​以修改容器的启动脚本,将每个本地容器中的转发端口转发到其他机器中所需的服务。

虽然这会造成一些复杂情况,因为您必须在每个容器中设置 ssh,并管理相应的密钥。

想想看,如果加密不是问题,ssh 就没有必要了。使用 socat or redir would probably be enough.

socat TCP4-LISTEN:61001,fork TCP4:othercontainer:61001