繁体   English   中英

如何将容器上的本地主机端口转发到主机上的本地主机?

[英]How can I forward localhost port on my container to localhost on my host?

我的主机上有一个守护进程在某个端口(即 8008)上运行,我的代码通常通过联系 localhost:8008 与守护进程交互。

我现在已经容器化了我的代码,但还没有容器化守护进程。 我如何将容器上的 localhost:8008 转发到运行容器的主机(以及守护进程)上的 localhost:8008。

以下是我主机上的netstat -tlnp 我希望容器将 localhost:2009 转发到主机上的 localhost:2009

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name            
tcp        0      0 127.0.0.1:2009          0.0.0.0:*               LISTEN      22547/ssh       
tcp6       0      0 :::22                   :::*                    LISTEN      -               
tcp6       0      0 ::1:2009                :::*                    LISTEN      22547/ssh            

因此,您需要考虑的方式是 Docker 容器有自己的网络堆栈(除非您明确告诉它与--net=host共享主机的堆栈)。 这意味着当与主机端口链接时,端口需要在 docker 容器内部和外部(文档)公开。 容器上暴露的端口需要显式绑定到主机端口(在 docker docker run命令中使用-p xxxx:yyyy )或隐式绑定(在EXPOSE中使用 EXPOSE 并在命令行中使用-P ),就像这里所说的. 如果您的 Dockerfile 不包含EXPOSE 8008 ,或者您没有在 docker run 命令中指定--expose 8008 ,那么即使您在 docker docker run命令中docker run -p 8008:8008 ,您的容器也无法与外界通信

因此,要在与容器上的 tcp/8008 链接的主机上获取 tcp/8008,您需要在EXPOSE 8008 (然后使用 docker docker build您的容器)或在 docker docker run command--expose 8008 此外,您需要使用-P隐式或-p 8008:8008将暴露的容器端口显式链接到主机端口。 执行此操作的示例docker run命令可能如下所示:

docker run -it --expose 8008 -p 8008:8008 myContainer

请记住,在-p 8008:8008命令行选项中,此操作的顺序是-p HOST_PORT:CONTAINER_PORT 另外,不要忘记您将无法从 Internet 上的另一台计算机通过 SSH 连接到您的容器,除非您在主机上的iptables 中也未阻止此端口。 我总是最终忘记了这一点并浪费了半个小时才想起我忘记了iptables -A INPUT ...用于主机上的特定 tcp 端口。 但是您应该能够在没有 iptables 规则的情况下从主机通过 SSH 连接到容器,因为它使用环回进行本地连接。 祝你好运!

TL;DR:您可以使用特殊的主机名host.docker.internal而不是localhost在容器内您想要访问localhost上的 localhost 的任何地方。 注意:

  • macOS 和 Windows 版本的 Docker Desktop 默认启用此功能。
  • Linux 主机(使用 Docker v 20.10 及更高版本 - 自 2020 年 12 月 14 日起)需要您在 Docker 命令中添加--add-host=host.docker.internal:host-gateway以启用该功能。
  • Linux 上的 Docker Compose 要求您将以下几行添加到容器定义中:
extra_hosts:
- "host.docker.internal:host-gateway"

完整答案:主机运行的是 MacOS 还是 Windows? 埋在 Docker Desktop 文档中的事实是 MacOS 上没有 docker0 网桥,而 Windows 上没有 docker0 网桥 显然这就是造成这种情况的原因。 在这两种情况下,解决方法(紧随其后,在标题为“用例和解决方法”的小节中给出)是使用特殊主机名host.docker.internal放置在容器内要访问localhost上的localhost的任何位置的本地主机。

如果主机是 Linux,则有一些仅限 Linux 的技术可以实现此目的 但是, host.docker.internal也可用于 Linux 主机,但必须先启用它。 有关说明,请参阅上面的 TL;DR 的 Linux 部分。

通过这种方法,在 OP 的情况下,应该使用host.docker.internal:8008而不是localhost:8008 请注意,这是在容器内运行的应用程序代码的代码或配置更改。 容器配置中无需提及端口。 不要尝试在 docker docker run命令行中使用-p--expose 不仅没有必要,而且如果您希望容器连接到的主机应用程序已经在侦听该端口,您的容器将无法启动。

在检查了答案并进行了一些调查之后,我相信有两种方法可以做到这一点,而这两种方法只适用于 Linux 环境。

第一个是在这篇文章中如何从 docker 容器访问主机端口

第二个应该设置你的--network=host当你 docker docker run或 docker docker container create 在这种情况下,您的 docker 将使用您在 Mac 中使用的相同网络接口。

但是,以上两种方式都不能在Mac中使用,所以我认为不可能从容器转发到Mac环境中的主机。 如果我错了,请纠正我。

我不确定您是否可以仅使用 docker 的设置来做到这一点。 如果我的理解是正确的,那么暴露端口不是你要找的。 相反,建立从容器到主机的 ssh 端口转发可能是答案。

您可以轻松使用-p 127.0.0.1:8008:8008并将容器的端口8008转发到本地主机的端口8008 一个示例 docker 命令是:

docker run -it -p 127.0.0.1:8008:8008 <image name>

如果您在本地计算机上执行此操作,则可以在启动容器时简单地将 .network 类型指定为host ( -.network host ),这将使您的主机与 docker 容器共享 .network 。

例如:

启动你的容器:

docker run -it --rm --network host <container>

在您的主机上,运行:

python3 -m http.server 8822

现在从你的容器运行:

curl 127.0.0.1:8822

如果一切顺利,您将在主机终端上看到流量。

Serving HTTP on 0.0.0.0 port 8822 (http://0.0.0.0:8822/) ...
127.0.0.1 - - [24/Jan/2023 22:37:01] "GET / HTTP/1.1" 200 -

docker run -d --name <NAME OF YOUR CONTAINER> -p 8008:8008 <YOUR IMAGE>

这会将容器中的端口8008发布到主机上的8008

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM