server.listen(port, '127.0.0.1') 无法访问容器化节点服务器

Posted

技术标签:

【中文标题】server.listen(port, \'127.0.0.1\') 无法访问容器化节点服务器【英文标题】:Containerized Node server inaccessible with server.listen(port, '127.0.0.1')server.listen(port, '127.0.0.1') 无法访问容器化节点服务器 【发布时间】:2016-05-26 15:57:31 【问题描述】:

我在 Docker 中建立了一个简单的 Node 服务器。

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://localhost:1337)时,我什么也看不到。

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

我已经尝试过的事情:

使用--expose 1337 标志运行

【问题讨论】:

您没有“使用--expose 运行”。您使用EXPOSE 指令构建映像,然后您使用--publish(或-p)运行。请参阅下面的答案。 【参考方案1】:

您的端口已正确公开,但您的服务器正在侦听容器内 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。

【讨论】:

在 0.0.0.0 上监听看起来很奇怪,不是很明显是什么意思。不过它似乎是默认值,因此您可以从 listen() 函数中省略该参数,我认为它更容易掌握 nodejs.org/api/… 监听 0.0.0.0 表示“监听所有接口”。这通常是矫枉过正,有时是安全问题,但通常是无害的。在 Docker 容器中是有意义的。 非常感谢,此解决方案解决了在 docker 中运行的任何类型的服务器(如 java 或 node.js express 服务器)的问题。在任何情况下,接口都必须是:0.0.0.0,其中端口是使用-P $PORT:$PORT/tcp 选项导出的端口,因此通常服务器会在运行时检查export HOST=0.0.0.0 非常感谢 - 我花了无数个小时才解决它! 非常感谢。我遇到了同样的问题,但使用 netty,我无法从容器外部访问它。有没有更好的方法来了解哪些网络接口容器边界,所以不要使用 0.0.0.0?【参考方案2】:

将 EXPOSE 1337 添加到 docker 文件中

如果您想将该端口“公开”给其他容器,

EXPOSE强制

作为BMitchcmets:

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

所以:

使用--expose 1337 标志运行

不完全是:你需要docker run它with -p 1337:1337

您需要:

构建一个包含EXPOSE 指令的映像(由-P 使用) 使用主机-p 1337:1337上发布的端口运行它

测试curl http://localhost:1337 是在容器内完成的(不需要EXPOSE 或发布)。 如果你想让它在 Linux 主机上工作,你需要EXPOSE+-P或者你需要-p 1337:1337。 要么。

单独声明它有利于记录意图,但不能单独做任何事情。

例如:

在该图中,8080 已公开,发布到 Linux 主机 8888。 如果该 Linux 主机不是实际主机,则需要将同一端口快速转发到实际主机。见“How to access tomcat running in docker container from browser?”。

如果 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,即the broadcast address or zero network。

【讨论】:

感谢您的评论,但正如我上面提到的,我已经尝试添加 EXPOSE 1337,但它也不起作用 @AssafShomer 两者都需要,这就是我回答的重点 @AssafShomer 我已经编辑了答案,以便更清楚地说明这一点。 谢谢,当然,我都试过了。即:使用 EXPOSE 1337 构建并使用 -p 1337:1337 运行,仍然没有。我更改了问题以反映这一点。 EXPOSE in Dockerfile 是完全没有必要的。它纯粹用作文档。表明意图是个好主意,但它也具有误导性,因为它根本没有做任何事情。也可以是评论。

以上是关于server.listen(port, '127.0.0.1') 无法访问容器化节点服务器的主要内容,如果未能解决你的问题,请参考以下文章

远程执行命令

Web进程无法在启动node.js后的60秒内绑定到$ PORT

server.listen() 的异步而不是 then()

非阻塞IO模板

python之socket运用之执行命令

进程池线程池 协程