有没有办法将绑定到 127.0.0.1 的 docker 容器端口暴露给主机?

Mar*_* An 8 docker docker-compose

我在绑定到127.0.0.1:8888.
我想将此端口公开给主机。
docker-compose 支持这个吗?

我尝试了以下docker-compose.yml但没有奏效。

expose: 
  - "8888"
ports:
  - "8888:8888"
Run Code Online (Sandbox Code Playgroud)

PS 在我的情况下,将服务绑定到容器内的 0.0.0.0 是不可能的。


更新:提供一个简单的例子:

docker-compose.yml

version: '3'
services:  
  myservice:
    expose: 
      - "8888"
    ports:
      - "8888:8888"
    build: .
Run Code Online (Sandbox Code Playgroud)

Dockerfile

FROM centos:7
RUN yum install -y nmap-ncat
CMD ["nc", "-l", "-k", "localhost", "8888"]
Run Code Online (Sandbox Code Playgroud)

命令:

$> docker-compose up --build
$> # Starting test1_myservice_1 ... done
$> # Attaching to test1_myservice_1

$> nc -v -v localhost 8888
$> # Connection to localhost 8888 port [tcp/*] succeeded!
TEST
$>
Run Code Online (Sandbox Code Playgroud)

TEST控制台中输入后连接被关闭,这意味着端口并没有真正暴露,尽管初始成功消息。我的真实服务也会出现同样的问题。
但是如果我绑定到容器内的 0.0.0.0(而不是本地主机),一切正常。

BMi*_*tch 10

通常答案是否定的,并且几乎在所有情况下,您都应该重新配置您的应用程序以侦听 0.0.0.0。任何试图避免更改应用程序以侦听容器内的所有接口的尝试都应被视为向您的项目增加技术债务的黑客行为。


为了扩展我的评论,默认情况下每个容器都在自己的网络命名空间中运行。容器内的环回接口与主机和其他容器中的环回接口是分开的。因此,如果您在容器内侦听 127.0.0.1,则该网络命名空间之外的任何内容都无法访问该端口。这与侦听 VM 上的环回并尝试从另一个 VM 连接到该端口没有什么不同,Linux 不允许您进行连接。

有几种解决方法:

  1. 您可以破解 iptables 来转发连接,但我个人会避免这种情况。Docker 在很大程度上基于对 iptables 规则的自动更改,因此您可能会与该自动化发生冲突或在下次重新创建容器时被破坏。
  2. 您可以在容器内设置一个代理,该代理侦听所有接口并转发到环回接口。像 nginx 这样的东西会起作用。
  3. 您可以在同一网络命名空间中获取内容。

最后一个有两种实现方式。在容器之间,您可以在另一个容器的网络命名空间中运行一个容器。这通常用于调试网络,也是 Pod 在 Kubernetes 中的工作方式。这是运行第二个容器的示例:

$ docker run -it --rm --net container:$(docker ps -lq) nicolaka/netshoot /bin/sh
/ # ss -lnt
State       Recv-Q Send-Q        Local Address:Port    Peer Address:Port
LISTEN      0      10                127.0.0.1:8888                  *:*
LISTEN      0      128             127.0.0.11:41469                  *:*
/ # nc -v -v localhost 8888
Connection to localhost 8888 port [tcp/8888] succeeded!
TEST
/ #
Run Code Online (Sandbox Code Playgroud)

请注意--net container:...(我曾经docker ps -lq在我的实验室中获取上次启动的容器 ID)。这使得两个独立的容器在同一个命名空间中运行。

如果您需要从 docker 外部访问它,您可以删除网络命名空间,并将容器直接附加到主机网络。对于一次性容器,这可以通过

docker run --net host ...
Run Code Online (Sandbox Code Playgroud)

在撰写中,这看起来像:

version: '3'
services:  
  myservice:
    network_mode: "host"
    build: .
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看有关此选项docker compose 文档。这在 swarm 模式下不受支持,并且您不会在此模式下发布端口,因为您将尝试在相同的网络命名空间之间发布端口。

旁注,expose不需要任何这些。它仅用于文档和一些自动化工具,但不会影响容器到容器网络,也不会影响发布特定端口的能力。