题 Docker端口未公开


我在Docker中设置了一个简单的节点服务器。

Dockerfile

FROM node:latest
RUN apt-get -y update
ADD example.js .
EXPOSE 1337   
CMD node example.js

example.js

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n'+new Date);
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

现在构建图像

$ docker build -t node_server。

现在在容器中运行

$ docker run -p 1337:1337 -d node_server
  $ 5909e87302ab7520884060437e19ef543ffafc568419c04630abffe6ff731f70

验证容器是否正在运行并且端口已映射:

$ docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
5909e87302ab        node_server         "/bin/sh -c 'node exa"   7 seconds ago       Up 6 seconds        0.0.0.0:1337->1337/tcp   grave_goldberg

现在让我们附加到容器并验证服务器是否在内部运行:

$ docker exec -it 5909e87302ab7520884060437e19ef543ffafc568419c04630abffe6ff731f70 / bin / bash

并在容器命令行中输入:

root@5909e87302ab:/# curl http://localhost:1337
Hello World
Mon Feb 15 2016 16:28:38 GMT+0000 (UTC)

看起来不错?

问题

当我在主机上执行相同的curl命令(或使用我的浏览器导航到 HTTP://本地主机:1337) 我什么也没看见。

知道为什么容器和主机之间的端口映射不起作用?

我已经尝试过的事情:

  • 跟着跑 --expose 1337 旗

29
2018-02-15 16:36


起源


你没有“跑 --expose“你用它构建一个图像 EXPOSE 指示, 然后 你跑 --publish (要么 -p)。请参阅下面的答案。 - VonC


答案:


您的端口正确暴露,但您的服务器正在侦听连接 127.0.0.1 在你的容器内:

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n'+new Date);
}).listen(1337, '127.0.0.1');

您需要像这样运行您的服务器:

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n'+new Date);
}).listen(1337, '0.0.0.0');

请注意0​​.0.0.0而不是127.0.0.1。


44
2018-02-15 17:25



听0.0.0.0看起来很奇怪,没有立即明显意味着什么。它似乎是默认值,所以你可以从中省略该参数 listen()功能,我认为更容易掌握 nodejs.org/api/... - Davos
收听0.0.0.0意味着“监听所有接口”。它通常是矫枉过正,有时是安全问题,但通常是无害的。它在Docker容器中是有意义的。 - Jim Stewart
非常感谢,这个解决方案解决了在诸如java或node.js express服务器之类的docker中运行的任何类型服务器的问题。接口必须在任何情况下: 0.0.0.0,其中端口是与其一起导出的端口 -P $PORT:$PORT/tcp 选项,通常服务器会检查 export HOST=0.0.0.0 在运行时。 - loretoparisi


将EXPOSE 1337添加到docker文件

EXPOSE 是 强制性 如果要将该端口“暴露”到其他容器。

BMitch 注释:

Expose 不需要发布端口或通过共享docker网络将容器连接到容器。
  它是用于发布所有端口的元数据 -P 并检查图像/容器。

所以:

跟着跑 --expose 1337 旗

不完全是:你需要 码头运行 它 -p 1337:1337

你需要:

  • 用它建立一个图像 EXPOSE 其中的指令(由...使用) -P
  • 要么 使用主机上发布的端口运行它 -p 1337:1337

考试 curl http://localhost:1337 是从容器内完成的(没有 EXPOSE 或需要发布)。
如果您希望它可以在Linux主机上运行,​​那么您需要 EXPOSE+-P  要么 你需要 -p 1337:1337
无论是。

声明单独暴露有利于记录意图,但不会单独执行任何操作。

例如:

https://i.stack.imgur.com/wmKgd.png

在该图中,8080是EXPOSE,发布到Linux主机8888。
如果该Linux主机不是实际主机,则需要将相同的端口快速发送到实际主机。见“如何从浏览器访问在docker容器中运行的tomcat?”。

如果localhost无法从Linux主机运行,请尝试其IP地址:

CID=$(docker run -p 1337:1337 -d node_server)
CIP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${CID})
curl http://${CIP}:1337

或者,如上所述,让您的服务器监听来自任何IP的连接: 0.0.0.0 是的 广播地址或零网络


17
2018-02-15 16:39



感谢您的评论,但正如我上面提到的,我已经尝试添加EXPOSE 1337,但它也不起作用 - Assaf Shomer
@AssafShomer你需要两者,这就是我的答案的全部要点 - VonC
@AssafShomer我已经编辑了答案,以便更清楚地说明这一点。 - VonC
@dav确切地说,您需要发布端口以使其对主机可见。 - VonC
@Davos好的。我编写了答案来说明公开和发布之间的区别(并引用0.0.0.0 IP) - VonC