有可能让Docker容器访问主机开放的端口吗?具体来说,我有MongoDB和RabbitMQ在主机上运行,我想在Docker容器中运行一个进程来监听队列并(可选地)写入数据库。

我知道我可以将一个端口从容器转发到主机(通过-p选项),并从Docker容器内部连接到外部世界(即互联网),但我不想将RabbitMQ和MongoDB端口从主机暴露给外部世界。

编辑:一些澄清:

Starting Nmap 5.21 ( http://nmap.org ) at 2013-07-22 22:39 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00027s latency).
PORT     STATE SERVICE
6311/tcp open  unknown

joelkuiper@vps20528 ~ % docker run -i -t base /bin/bash
root@f043b4b235a7:/# apt-get install nmap
root@f043b4b235a7:/# nmap 172.16.42.1 -p 6311 # IP found via docker inspect -> gateway

Starting Nmap 6.00 ( http://nmap.org ) at 2013-07-22 20:43 UTC
Nmap scan report for 172.16.42.1
Host is up (0.000060s latency).
PORT     STATE    SERVICE
6311/tcp filtered unknown
MAC Address: E2:69:9C:11:42:65 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.31 seconds

我必须这样做才能在容器内获得任何互联网连接:我的防火墙阻止了从docker容器到外部的网络连接

编辑:最终我使用管道创建了一个自定义网桥,并让服务侦听网桥IP。我使用这种方法而不是让MongoDB和RabbitMQ在docker桥上监听,因为它提供了更大的灵活性。


当前回答

一个简单但相对不安全的方法是使用——net=host选项来运行docker。

此选项使容器使用主机的网络堆栈。然后,只需使用“localhost”作为主机名,就可以连接到主机上运行的服务。

这更容易配置,因为你不需要配置服务来接受来自docker容器的IP地址的连接,你也不需要告诉docker容器一个特定的IP地址或主机名来连接,只需要一个端口。

例如,您可以通过运行以下命令来测试它,该命令假设您的映像名为my_image,映像包含telnet实用程序,并且您想要连接的服务位于端口25上:

docker run --rm -i -t --net=host my_image telnet localhost 25

如果您考虑这样做,请参阅本页上关于安全的警告:

https://docs.docker.com/articles/networking/

它说:

--net=host -- Tells Docker to skip placing the container inside of a separate network stack. In essence, this choice tells Docker to not containerize the container's networking! While container processes will still be confined to their own filesystem and process list and resource limits, a quick ip addr command will show you that, network-wise, they live “outside” in the main Docker host and have full access to its network interfaces. Note that this does not let the container reconfigure the host network stack — that would require --privileged=true — but it does let container processes open low-numbered ports like any other root process. It also allows the container to access local network services like D-bus. This can lead to processes in the container being able to do unexpected things like restart your computer. You should use this option with caution.

其他回答

如果MongoDB和RabbitMQ运行在主机上,那么端口应该已经公开,因为它不在Docker中。

为了将端口从容器公开到主机,不需要使用-p选项。默认情况下,所有端口都是公开的。-p选项允许您从容器向主机外部公开一个端口。

所以,我的猜测是你根本不需要-p,它应该可以正常工作:)

TLDR;

只适用于本地发展,请采取以下措施:

在笔记本电脑/电脑/PC/Mac上启动服务或SSH隧道。 构建/运行Docker镜像/容器以连接到主机名host.docker.internal:<hostPort>

注意:还有gateway.docker.internal,我没有尝试过。

END_TLDR;

例如,如果你在你的容器中使用这个:

PGPASSWORD=password psql -h localhost -p 5432 -d mydb -U myuser

改成这样:

PGPASSWORD=password psql -h host.docker.internal -p 5432 -d mydb -U myuser

这将神奇地连接到主机上运行的服务。不需要使用——net=host或-p "hostPort:ContainerPort"或-p

背景

详情见:https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

我将此与SSH隧道一起使用到Windows 10上的AWS RDS Postgres实例。我只需要在容器中使用localhost:containerPort更改为host.docker.internal:hostPort。

docker主机向所有容器公开一个适配器。假设你使用的是最新的ubuntu,你可以运行

ip addr

这将为您提供一个网络适配器列表,其中一个看起来像这样

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 22:23:6b:28:6b:e0 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
inet6 fe80::a402:65ff:fe86:bba6/64 scope link
   valid_lft forever preferred_lft forever

您需要告诉rabbit/mongo绑定到该IP(172.17.42.1)。在此之后,您应该能够从容器中打开到172.17.42.1的连接。

对于较新版本的Docker,这对我来说是可行的。像这样创建隧道(注意开始时的0.0.0.0):

-L 0.0.0.0:8080:localhost:8081

这将允许任何访问您的计算机的人连接到端口8080,从而访问所连接服务器上的端口8081。

然后,在容器内部使用"host.docker.internal",例如:

curl host.docker.internal:8081

一个简单但相对不安全的方法是使用——net=host选项来运行docker。

此选项使容器使用主机的网络堆栈。然后,只需使用“localhost”作为主机名,就可以连接到主机上运行的服务。

这更容易配置,因为你不需要配置服务来接受来自docker容器的IP地址的连接,你也不需要告诉docker容器一个特定的IP地址或主机名来连接,只需要一个端口。

例如,您可以通过运行以下命令来测试它,该命令假设您的映像名为my_image,映像包含telnet实用程序,并且您想要连接的服务位于端口25上:

docker run --rm -i -t --net=host my_image telnet localhost 25

如果您考虑这样做,请参阅本页上关于安全的警告:

https://docs.docker.com/articles/networking/

它说:

--net=host -- Tells Docker to skip placing the container inside of a separate network stack. In essence, this choice tells Docker to not containerize the container's networking! While container processes will still be confined to their own filesystem and process list and resource limits, a quick ip addr command will show you that, network-wise, they live “outside” in the main Docker host and have full access to its network interfaces. Note that this does not let the container reconfigure the host network stack — that would require --privileged=true — but it does let container processes open low-numbered ports like any other root process. It also allows the container to access local network services like D-bus. This can lead to processes in the container being able to do unexpected things like restart your computer. You should use this option with caution.