使用PM2启动Node.js生产环境时Docker端口未绑定问题
解决Docker+PM2生产环境端口无法绑定的问题
从你的描述和提供的配置来看,主要有两个关键点导致端口无法绑定,下面逐一分析并给出解决方案:
1. Docker启动命令错误导致端口未映射
观察你的docker ps输出,Node.js容器的名称是nodeapiboilerplate_provision_run_1,这个命名格式说明你是用docker-compose run provision命令启动的生产服务。而**docker-compose run默认不会应用服务定义中的端口映射规则**,这就是为什么容器的PORTS列是空的(对比MongoDB容器的端口映射)。
解决方案:
- 使用
docker-compose up命令启动服务,这会严格按照docker-compose.yml中的配置创建端口映射:
(docker-compose up -d provision-d参数让容器在后台运行) - 如果必须使用
docker-compose run,需要加上--service-ports参数来启用端口映射:docker-compose run --service-ports provision
2. PM2 Cluster模式在Docker容器中的适配问题
你的PM2配置使用了cluster模式,虽然这个模式在宿主机上可以利用多核CPU,但在Docker容器中意义不大——Docker本身提供了容器级别的水平扩展(比如docker-compose up --scale provision=3来启动3个服务实例),容器内单进程更符合Docker的设计理念。另外,Cluster模式下如果进程监听逻辑有问题,也可能导致端口无法正常对外暴露。
解决方案:
修改process.json,将执行模式改为fork,并设置实例数为1:
{ "apps" : [{ "name" : "node-api-boilerplate", "script" : "./src/server.js", "exec_mode" : "fork", "exec_interpreter": "babel-node", "instances" : 1, "merge_logs" : true }] }
同时,建议在server.js中显式指定监听地址为0.0.0.0(虽然Express默认监听0.0.0.0,但显式声明可以避免潜在的环境差异问题):
app.listen(PORT, '0.0.0.0', () => { logger.info(`Listening on port ${PORT} (bound to 0.0.0.0)`); });
验证步骤
修改配置后,按以下步骤验证:
- 重启生产容器:
docker-compose down && docker-compose up -d provision - 再次运行
docker ps,确认Node.js容器的PORTS列显示0.0.0.0:3000->3000/tcp - 查看容器日志确认服务启动:
docker logs prod_node_api,应该能看到"Listening on port 3000"的日志 - 测试API是否可访问:比如用
curl http://localhost:3000/api/v1(根据你的路由调整)
内容的提问来源于stack exchange,提问作者André Andrade




