在一个活的Docker容器上暴露一个端口

我正在尝试创build一个充当虚拟机的Docker容器。 我知道我可以使用Dockerfile中的EXPOSE指令来公开一个端口,并且我可以在docker run中使用-p标志来分配端口,但是一旦容器实际运行,是否有一个命令可以打开/映射额外的端口?

例如,假设我有一个运行sshd的Docker容器。 其他人使用容器ssh的和安装httpd。 有没有办法在容器上公开端口80,并将其映射到主机上的端口8080,以便人们可以访问容器中运行的Web服务器,而无需重新启动它?

你不能通过Docker来做到这一点,但你可以从主机访问容器的未公开端口。

如果你有一个在8000端口上运行的容器,你可以运行

 wget http://container_ip:8000 

要获取容器的IP地址,请运行2个命令:

 docker ps docker inspect container_name | grep IPAddress 

在内部,当你运行一个镜像的时候,Docker会调用iptables来调用iptables,所以在这个方面可能会有一些变化。

在本地主机端口8001上公开容器的端口8000:

  iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000 

有一种方法可以解决这个问题,就是使用你想要的端口映射来设置另一个容器,并比较iptables-save命令的输出(不过,我必须删除一些强制stream量通过docker的选项代理)。

注意:这是颠覆docker,所以应该做的是意识到它可能会创造蓝烟

要么

另一种方法是查看(新的?后期0.6.6?)-P选项 – 它将使用随机的主机端口,然后将其连接起来。

要么

与0.6.5,你可以使用LINKsfunction来调出一个新的容器,与现有的谈判,一些额外的中继到该容器的-p标志? (我还没有使用LINK)

要么

与docker0.11? 你可以使用docker run --net host ..将容器直接连接到主机的networking接口(即networking不是名称间隔的),因此你在容器中打开的所有端口都是公开的。

这是我会做的:

  • 提交活动容器。
  • 再次运行容器与新的形象,打开端口(我build议安装一个共享卷,并打开SSH端口以及)
 sudo docker ps sudo docker commit <containerid> <foo/live> sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t <foo/live> /bin/bash 

这是另一个想法。 使用SSH进行端口转发; 当你的Docker主机是虚拟机时,这也有利于在OS X(也可能是Windows)中工作。

 docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip> 

至less在Docker 1.4.1上,IPtables hacks不起作用。

最好的办法是运行另一个容器与暴露的端口和socat接力。 这是我用SQLPlus(临时)连接到数据库的方法:

 docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus 

Dockerfile:

 FROM debian:7 RUN apt-get update && \ apt-get -y install socat && \ apt-get clean USER nobody CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521 

虽然无法公开现有容器的新端口,但可以在同一个Dockernetworking中启动一个新的容器,并将stream量转发到原始容器。

 # docker run \ --rm \ -p $PORT:1234 \ verb/socat \ TCP-LISTEN:1234,fork \ TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT 

工作示例

启动监听端口80的Web服务,但不要暴露其内部端口80(oops!):

 # docker run -ti mkodockx/docker-pastebin # Forgot to expose PORT 80! 

find它的DockernetworkingIP:

 # docker inspect 63256f72142a | grep IPAddress "IPAddress": "172.17.0.2", 

启动8080端口的verb/socat ,并将TCPstream量转发到该端口80:

 # docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80 

您现在可以访问http:// localhost:8080 /上的pastebin,并且您的请求转到socat:1234 ,并将其转发到pastebin:80 ,并且响应以相反的方式传播相同的path。

我不得不处理这个相同的问题,并能够解决它,而不会停止我的任何运行容器。 截至2016年2月,这是一个使用Docker 1.9.1的解决scheme。 无论如何,这个答案是@ ricardo-branco的答案的详细版本,但更深入的新用户。

在我的场景中,我想临时连接到在容器中运行的MySQL,并且由于其他应用程序容器已链接到该容器,停止,重新configuration和重新运行数据库容器是一个非启动器。

因为我想从外部访问MySQL数据库(通过SSH隧道从Sequel Pro中),我将使用主机上的端口33306 。 (不是3306 ,以防万一有一个外部MySQL实例在运行。)

大约一个小时的调整iptablescertificate是徒劳的,即使:

一步一步,这是我做的:

 mkdir db-expose-33306 cd db-expose-33306 vim Dockerfile 

编辑dockerfile ,把它放在里面:

 # Exposes port 3306 on linked "db" container, to be accessible at host:33306 FROM ubuntu:latest # (Recommended to use the same base as the DB container) RUN apt-get update && \ apt-get -y install socat && \ apt-get clean USER nobody EXPOSE 33306 CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306 

然后build立图像:

 docker build -t your-namespace/db-expose-33306 . 

然后运行它,链接到正在运行的容器。 (使用-d代替-rm来保持它在后台直到明确停止和删除,我只希望它在这种情况下暂时运行。

 docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306 your-namespace/db-expose-33306 

为了增加接受的答案 iptables解决scheme,我必须在主机上运行两个命令才能将其打开到外部世界。

 HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443 HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https 

注意:我打开端口https(443),我的docker内部IP是172.17.0.2

注2:这些规则和时间,只会持续到容器重新启动

您可以使用像Weave Net这样的覆盖networking,它将为每个容器分配一个唯一的IP地址,并隐式地将所有端口暴露给networking的每个容器部分。

编织还提供主机networking集成 。 它在默认情况下是禁用的,但是,如果您还想从主机访问容器IP地址(及其所有端口),则可以运行简单的运行weave expose

完全披露:我在Weaveworks工作。

您可以使用SSH创build一个隧道并将您的容器暴露在主机中。

从容器到主机,从主机到容器,都可以这样做。 但是你需要一个像OpenSSH这样的SSH工具(一个是客户端,一个是另一个服务器)。

例如,在容器中,你可以做

 $ yum install -y openssh openssh-server.x86_64 service sshd restart Stopping sshd: [FAILED] Generating SSH2 RSA host key: [ OK ] Generating SSH1 RSA host key: [ OK ] Generating SSH2 DSA host key: [ OK ] Starting sshd: [ OK ] $ passwd # You need to set a root password.. 

您可以从此行(容器中)find容器IP地址:

 $ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g' 172.17.0.2 

然后在主持人,你可以做:

 sudo ssh -NfL 80:0.0.0.0:80 root@172.17.0.2 

有一个方便的HAProxy包装。

 docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy 

这会为目标容器创build一个HAProxy。 十分简单。

首先阅读里卡多的回应。 这对我有效。

但是,如果使用docker-compose启动正在运行的容器,则会出现这种情况。 这是因为docker构成(我运行docker1.17)创build一个新的networking。 解决这种情况的方法是

docker network ls

然后追加下面的docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name

无法进行实时端口映射,但是您可以通过多种方式为Docker容器提供像虚拟机一样的真实接口。

Macvlan接口

Docker现在包含一个Macvlannetworking驱动程序 。 这将Dockernetworking连接到“真实世界”界面,并允许您将该networking地址直接分配给容器(如虚拟机桥接模式)。

 docker network create \ -d macvlan \ --subnet=172.16.86.0/24 \ --gateway=172.16.86.1 \ -o parent=eth0 pub_net 

pipework还可以将真实接口映射到容器中,或者在老版本的Docker中设置子接口 。

路由IP的

如果您拥有networking的控制权,您可以将其他networking路由到您的Docker主机以在容器中使用。

然后,您将该networking分配给容器,并设置您的Docker主机通过dockernetworking路由数据包。

共享主机界面

--net host选项允许将主机接口共享到一个容器中,但由于共享性质,这可能不是一个主机上运行多个容器的好设置。

对我来说,最好的方法是直接更改容器的configuration文件,请参阅如何将端口映射分配给现有的Docker容器? ,按下Ctrl + F并find“json”

使用以下命令启动您的容器:

 docker run -d -p <host_port>:<container_exposed_port> -t <image_name> 
  • 是您的localhost端口号。
  • 是该容器的泊坞窗文件中公开的端口号。

还有一个相当新的-P标志,告诉Docker将我们容器内的任何必需的networking端口映射到我们的主机。 这可以帮助您从外部世界中查看您的Web应用程序。

当你绑定到一个端口时,Docker会为你redirect它。 使用Docker port命令,你会看到如下所示:

 docker port 5019f8e8f902 5000/tcp -> 0.0.0.0:49162 5555/tcp -> 0.0.0.0:49163 8080/tcp -> 0.0.0.0:49164