在一个活的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