5

我有一个无法解决的端口转发问题。我在 VM 中运行 Linux,并且正在使用该 VM 中的 docker。例如,当我尝试从 docker compose 设置端口转发时:

ports:
   - "3080:3080"

它仅在容器中运行的应用程序正在侦听 0.0.0.0:3080 的情况下才有效。问题是,我正在 dockerizing 的大多数应用程序都在监听 localhost。0.0.0.0 以外的任何接口都会导致端口转发不起作用。您知道为什么会发生这种情况或如何解决这个问题吗?

我在跑:

Docker 版本 17.05.0-ce,构建 89658be

docker-compose 版本 1.17.1,构建未知

谢谢

PS我找到了一个临时的解决方法。我为容器指定网络模式“主机”,强制容器使用主机操作系统网络,但这种方法在 MacOS 上不起作用。

4

3 回答 3

10

“如何解决”是将应用程序设置为监听 0.0.0.0。对于简短的脚本,您经常会在 main 函数中看到这个硬编码(甚至是库中隐含的),但对于“真实”服务器来说,这是一个非常常见的选项,并且您可能会通过命令行选项公开这种事情或环境变量。

就“为什么”而言:在 Docker 内部,每个容器都运行在一个隔离的网络命名空间中。例如,如果您尝试:

$ docker run --rm busybox ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0

这里重要的是每个容器都有自己的localhost,不同于其他容器localhost和主机的localhost。因此,如果您将容器设置为将 (2)绑定到 127.0.0.1,它将只接受来自同一容器内 127.0.0.1 的连接。

同时,Docker 为您运行一个网络地址转换 (NAT) 层。如果您docker run -p 3080:3080按照显示的方式运行,然后(从主机)运行iptables -vL,您会发现其中一件事是端口转发规则,它将入站请求路由到主机上的端口 3080,到容器 IP 地址(在我的例如 172.17.0.2),通过 device docker0,到端口 3080。在容器的网络地址空间中,它将在人工容器本地eth0接口上接收入站连接;如果您要在套接字上调用getsockname (2),您会看到 172.17.0.2 地址。 您的进程必须接受容器本地eth0接口或所有接口上的连接,才能从容器外部访问。

所有这些都是实现细节;你几乎永远不需要真正担心它。例如,由于 172.17.0.0/16 地址是 Docker 人为管理的,所以你无法从 off-host 访问它们,它们会在不同docker run的 s 之间变化;对于容器之间的通信(在同一个 Docker 内部网络上),您确实间接使用它们,但通常通过 Docker 提供的 DNS 服务(因此连接到other-container-name作为主机名,这将恰好被解析为 172.17.0.3)。如果您查看一些特别涉及的服务器启动序列的详细输出,您会看到它们迭代接口并显式绑定到所有接口;但对于大多数应用程序来说,Docker 空间中的正确答案就是始终绑定到 0.0.0.0。

于 2018-10-13T16:06:54.123 回答
1

我建议在 docker-compose 文件中使用网络模式桥接器

driver: bridge
于 2018-10-13T14:57:30.137 回答
1

理想情况下,您可以将容器内的服务配置为侦听0.0.0.0:3080而不是 localhost127.0.0.1:3080

但是,如果像我最近一样,您正在使用硬编码的第三方服务来侦听本地主机端口(例如127.0.0.1:3080),您可以使用容器内的socat实用程序将容器的外部端口转发到内部服务。例如,要让服务在 localhost 端口上侦听,127.0.0.1:3080可以从容器外部的端口访问3081

apt-get update && apt-get install -y socat

然后

socat TCP-LISTEN:3081,fork TCP:127.0.0.1:3080

然后,您可以通过 docker 端口转发从容器外部访问服务,即docker run -p 3080:3081(或ports: ["3080:3081"]在 docker-compose.yml 中),将 3080 替换为方便的任何端口号。

于 2021-02-16T21:37:27.420 回答