在实时Docker容器上公开端口

reb*_*rdt 384 docker

我正在尝试创建一个充当完整虚拟机的Docker容器.我知道我可以使用Dockerfile中的EXPOSE指令来公开一个端口,我可以使用-pflag docker run来分配端口,但是一旦容器实际运行,是否有命令打开/映射其他端口?

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

Sve*_*eit 317

您无法通过Docker执行此操作,但可以从主机访问容器的未公开端口.

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

wget http://container_ip:8000
Run Code Online (Sandbox Code Playgroud)

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

docker ps

docker inspect container_name | grep IPAddress
Run Code Online (Sandbox Code Playgroud)

在内部,Docker会在你运行图像时弹出来调用iptables,所以可能会有一些变化.

在localhosts端口8001上公开容器的端口8000:

 iptables -t nat -A  DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000
Run Code Online (Sandbox Code Playgroud)

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

注意:这是颠覆码头,所以应该意识到它可能会产生蓝烟

要么

另一种选择是查看(新的?post 0.6.6?) - P选项 - 它将使用随机主机端口,然后连接它们.

要么

使用0.6.5,您可以使用LINKs功能调出一个与现有容器对话的新容器,还有一些中继到该容器的-p标志?(我还没有用过LINK)

要么

与docker 0.11?您可以使用docker run --net host ..将容器直接连接到主机的网络接口(即,网络不是名称间隔),因此您在容器中打开的所有端口都会被暴露.

  • 至少这似乎不适用于docker 1.3.0.使用-p运行docker时会创建DOCKER DNAT规则,但手动添加它似乎不允许连接.在容器运行时奇怪地删除规则似乎并没有阻止它工作...... (6认同)
  • 谢谢.我被一种安全感所迷惑,即未曝光的端口是安全的. (4认同)
  • @ ericson.cepeda而不是调用`jq`和`sed`你可以使用`docker inspect`的`-f`选项:`CONTAINER_IP = $(docker inspect -f'{{.NetworkSettings.IPAddress}}'container_name)` (4认同)

bos*_*101 131

这就是我要做的事情:

  • 提交活动容器.
  • 使用新映像再次运行容器,端口打开(我建议安装共享卷并打开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
Run Code Online (Sandbox Code Playgroud)

  • 我的问题的关键部分是,这需要在不重新启动容器的情况下发生...转移到新容器可能会保留文件,但会有效地终止任何正在运行的进程,并且类似于在物理计算机上重新启动.没有发生这种情况,我需要做到这一点.谢谢你! (27认同)
  • 你为什么要运行`sudo docker`而不仅仅是`docker`? (6认同)

Rob*_*obM 39

虽然您无法公开现有容器的新端口,但您可以在同一个Docker网络中启动一个新容器,并将其转发到原始容器.

# docker run \
  --rm \
  -p $PORT:1234 \
  verb/socat \
    TCP-LISTEN:1234,fork \
    TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT
Run Code Online (Sandbox Code Playgroud)

工作示例

启动Web服务端口80上监听,但千万不能暴露其内部端口80(哎呀!):

# docker run -ti mkodockx/docker-pastebin   # Forgot to expose PORT 80!
Run Code Online (Sandbox Code Playgroud)

找到它的Docker网络IP:

# docker inspect 63256f72142a | grep IPAddress
                    "IPAddress": "172.17.0.2",
Run Code Online (Sandbox Code Playgroud)

verb/socat在端口8080暴露的情况下启动,并使其将TCP流量转发到该IP的端口80:

# docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80
Run Code Online (Sandbox Code Playgroud)

您现在可以访问http:// localhost:8080 /上的pastebin ,并将您的请求socat:1234转发到该请求pastebin:80,并且响应以相反的方式传递相同的路径.

  • 非常聪明!然而,最好使用`verb/socat:alpine`,因为它的图像有5%的占用空间(除非你遇到[libc或DNS不兼容](https://github.com/gliderlabs/docker-alpine/blob) /master/docs/caveats.md)). (6认同)
  • 还有'alpine/socat` (3认同)
  • 极好的答案。简单,只需一眼就能完成工作,而不会受到任何恶意攻击。 (3认同)
  • 这对我来说效果很好,谢谢!自从我在创建网络的docker组合中启动了未公开的容器以来,我必须在verb / socat启动命令中添加--net myfoldername_default。 (2认同)

小智 34

IPtables黑客行为不起作用,至少在Docker 1.4.1上是这样.

最好的方法是运行带有暴露端口的另一个容器并使用socat中继.这就是我用SQLPlus(临时)连接数据库所做的事情:

docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 你可能想试试[apline/socat](https://hub.docker.com/r/alpine/socat/).它预装了socat并接受socat选项作为命令,因此您根本不需要编写Dockerfile. (4认同)
  • iptables hack应该从主机而不是docker容器运行。它实质上是将对主机上某些端口的请求转发到适当的Docker容器端口中。它根本不是特定于docker的,您可以对完全不同的主机执行此操作。您可以将代码格式添加到Docker文件中吗?似乎很有用。 (2认同)

Sco*_*son 32

这是另一个想法.使用SSH进行端口转发; 当您的Docker主机是VM时,这也可以在OS X(可能还有Windows)中运行.

docker exec -it <containterid> ssh -R5432:localhost:5432 <user>@<hostip>
Run Code Online (Sandbox Code Playgroud)

  • 在我的情况下,正在运行的docker镜像没有二进制ssh (3认同)

Exc*_*bur 8

我不得不处理同样的问题,并且能够在不停止任何正在运行的容器的情况下解决它.使用Docker 1.9.1,这是截至2016年2月的最新解决方案.无论如何,这个答案是@ ricardo-branco答案的详细版本,但对新用户更为深入.

在我的场景中,我想暂时连接到在容器中运行的MySQL,并且由于其他应用程序容器已链接到它,因此停止,重新配置和重新运行数据库容器是不可能的.

由于我想从外部访问MySQL数据库(从Sequel Pro通过SSH隧道),我将33306在主机上使用端口.(不是3306,以防万一外部MySQL实例正在运行.)

大约一个小时的调整iptables证明没有结果,即使:

一步一步,这就是我做的:

mkdir db-expose-33306
cd db-expose-33306
vim Dockerfile
Run Code Online (Sandbox Code Playgroud)

编辑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
Run Code Online (Sandbox Code Playgroud)

然后构建图像:

docker build -t your-namespace/db-expose-33306 .
Run Code Online (Sandbox Code Playgroud)

然后运行它,链接到正在运行的容器.(在明确停止和删除之前,请使用-d而不是将-rm其保留在后台.我只希望它在这种情况下暂时运行.)

docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306  your-namespace/db-expose-33306
Run Code Online (Sandbox Code Playgroud)


dst*_*stj 6

要添加到可接受的答案 iptables解决方案中,我必须在主机上再运行两个命令以将其打开。

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
Run Code Online (Sandbox Code Playgroud)

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

注意2:这些规则和临时规则仅会持续到容器重新启动为止


Pau*_*gel 6

根据Robm 的回答,我创建了一个 Docker 映像和一个名为 的 Bash 脚本portcat

使用portcat,您可以轻松地将多个端口映射到现有的 Docker 容器。使用(可选)Bash 脚本的示例:

curl -sL https://raw.githubusercontent.com/archan937/portcat/master/script/install | sudo bash
portcat my-awesome-container 3456 4444:8080
Run Code Online (Sandbox Code Playgroud)

就这样吧!Portcat 正在映射:

  • 端口3456my-awesome-container:3456
  • 端口4444my-awesome-container:8080

请注意,Bash 脚本是可选的,以下命令:

ipAddress=$(docker inspect my-awesome-container | grep IPAddress | grep -o '[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}' | head -n 1)
docker run -p 3456:3456 -p 4444:4444 --name=alpine-portcat -it pmelegend/portcat:latest $ipAddress 3456 4444:8080
Run Code Online (Sandbox Code Playgroud)

我希望portcat对你们有用。干杯!


ton*_*ton 5

您可以使用 SSH 创建隧道并在您的主机中公开您的容器。

您可以通过两种方式来实现,从容器到主机,从主机到容器。但是你需要一个像 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..
Run Code Online (Sandbox Code Playgroud)

您可以从这一行(在容器中)找到容器 IP 地址:

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

然后在主机中,您可以执行以下操作:

sudo ssh -NfL 80:0.0.0.0:80 root@172.17.0.2
Run Code Online (Sandbox Code Playgroud)