【问题标题】:How can I redirect a single port in a docker container to the container's host?如何将 docker 容器中的单个端口重定向到容器的主机?
【发布时间】:2017-01-11 08:14:22
【问题描述】:

为了使项目的开发更容易,我在 docker 容器中放置了一些它所依赖的服务。这使得项目配置中的“localhost”在传递给其中一个容器时意味着不同。

编辑

明确地说,我正在尝试将容器的端口之一转发到主机,因此当容器中运行的进程尝试访问 localhost:5432 时,它连接到主机的端口5432。

结束

我正在使用

HOST_IP=`ip route | grep default | awk '{ printf "%s",$3 }'`
cat /etc/hosts | sed "s/127.0.0.1/$HOST_IP/" > /tmp/etc_hosts
cp /tmp/etc_hosts /etc/hosts

将任何以“localhost”为目标的东西重定向到容器的主机。它在这种情况下工作,但我更愿意找到一种方法只为所需的端口执行此操作,因为我预计它在其他情况下不会工作。

这就是我想出的办法,但它不起作用;当容器中的连接是到 localhost:5432 时,它会尝试连接到容器的 5432 而不是主机的:

# --- These are the things that should make redirecting port 5432 to the host machine
#     work, provided the container is run in privileged mode.
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.route_localnet=1
iptables -t nat -A PREROUTING -p tcp --dport 5432 -j DNAT --to 172.19.0.1:5432
iptables -A FORWARD -d 172.19.0.1 -p tcp --dport 5432 -j ACCEPT
iptables -t nat -A POSTROUTING -j MASQUERADE

【问题讨论】:

  • 你为什么不直接使用-p
  • @RandallFlagg,见编辑。

标签: docker iptables


【解决方案1】:

如果我理解得很好,对于开发,您希望 localhost 解析到特定容器,包括从另一个容器调用它时。

主机转发

正如您所提到的,重写您的 hosts 文件不是一个好主意,因为如果您将 localhost 设计为不同于...本地主持人。

但您可以考虑一些解决方案。

Docker 工具箱

如果使用Docker Toolbox 运行docker,或者使用Virtual Box 在虚拟机上自己运行,则中间虚拟机是可见的,因此localhost 将代表它。您必须运行容器,公开此端口,然后在 Virtualbox 中设置端口转发。如果我以 Wordpress 为例:

  1. docker run -p 80:80 --name website -d wordpress
  2. Virtual Box -> 你的 docker VM(通常称为 default)-> 网络 -> 适配器 1 -> 端口转发 -> 创建从主机 8080 到来宾 80 的映射

它将使 Wordpresshttp://localhost:8080 可用。请注意MacOS下,内核限制非特权端口转发(1024以下的端口)。

这个端口转发可以在命令行中创建,如果你想把它放在脚本里:
VBoxManage modifyvm "default" --natpf1 "app,tcp,,8080,,80"

Docker for Windows/Docker for Mac

如果通过Docker for Windows/Docker for Mac(或直接在Linux 下)而不是Docker Toolbox 运行docker,则可以使用-p 参数运行容器,如指定通过 Scott 的帖子,你的服务将在 localhost 的这个端口上可用(因为中间虚拟机是透明的,或者 Linux 下没有 VM):

docker run -p 5432:5432 --name myapp -d myimage 将使 myapplocalhost:5432 上可用。

socat(或 iptables)

您可以通过这种方式在您的 主机 上运行 socat,将特定端口上的通信转发到您的容器:

socat TCP-LISTEN:5432,fork,reuseaddr,user=node,group=node,mode=777 TCP:172.19.0.1:5432 &

(其中 172.19.0.1 是您的容器 IP)

集装箱转发

--网络

您的容器有自己的hosts 文件,您可以通过发出这样的命令来查看:

docker run ubuntu cat /etc/hosts

您可以使用--add-host 参数向hosts 添加条目:

docker run --add-host domain:1.2.3.4 --add-host domain2:5.6.7.8 ubuntu cat /etc/hosts

但是这个解决方案对于localhost 是没有用的,因为它不会删除之前的localhost 关联。您正在寻找的(以及更清洁的)是参数--network=host,它允许容器共享主机的网络接口:

docker run --network=host ubuntu

这样,您的容器将能够使用其端口调用 localhost 上的其他容器服务。

正确的方法

当然,实现所需的正确方法是将容器链接在一起并使用它们的链接名称而不是 localhost

docker run -d  --name mariadb -e MYSQL_ROOT_PASSWORD=password mariadb 
docker run -d --name="wordpress" -p 8080:80 -e WORDPRESS_DB_PASSWORD=password --link mariadb:mysql wordpress

在这种情况下,Wordpress 容器将在其hosts 文件中有一个 mysql 条目,指向 mariadb 容器 IP 地址.要查看它,请在 Wordpress 容器中打开一个bash 会话并自己查看。

docker exec -ti wordpress bash
#cat /etc/hosts

【讨论】:

  • 对不起,我不清楚,但没有。请查看我对问题的编辑。
  • 啊,您的编辑使其更清晰,您是对的。我建议的 host=network 参数可以到达另一个容器(或在 Docker VM 上运行的端口上的服务),但不能在主机上......我认为它可以与 Docker for Mac 一起使用,但测试证明它没有。这在此处讨论:forums.docker.com/t/should-docker-run-net-host-work/14215/26 有人建议,如果使用基于 VirtualBox 的解决方案,例如 Docker Toolbox,则使用类似 ssh -t -R5432:localhost:5432 docker@$(docker-machine ip default) 的反向隧道来完成连接 VM港口。祝你好运!
【解决方案2】:

向我们展示您是如何启动容器的

端口映射可以在你的 docker run 命令中发生:-p hostport:containerport

docker run  -p 5432:5432 --name mycontainer -d myimage

【讨论】:

  • 我正在尝试做相反的事情,相当于 -p containerport:hostport
猜你喜欢
  • 2014-03-01
  • 2014-09-01
  • 2013-07-20
  • 1970-01-01
  • 1970-01-01
  • 2017-01-29
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
相关资源
最近更新 更多