Docker部署Node服务server.js读不到环境变量且Mongo连接报错
问题根因
核心问题出在启动脚本的写法错误,导致server.js根本没有在Docker容器内部运行,你实际访问到的5000端口服务是运行在Docker外部的宿主机上的,因此引发两个连锁问题:
- 宿主机上运行的Node进程没有注入docker-compose为
test-app容器配置的MONGO_USER等环境变量,读取结果自然为undefined - 宿主机进程不在Docker Compose创建的内部虚拟网络中,无法通过Docker内置DNS解析到
mongo这个服务域名,因此抛出MongooseServerSelectionError: getaddrinfo ENOTFOUND mongo错误
你在package.json里写的启动命令是:
"scripts": { "start": "nodemon index.js && nodemon server.js", "dev": "nodemon index.js && nodemon server.js" }
Shell语法中&&是顺序执行符,只有前一个命令执行完成、正常退出后才会执行后一个命令。而nodemon index.js是常驻进程,启动后会一直监听端口和文件变化,永远不会主动退出,因此后面的nodemon server.js永远不会在容器内被执行。你之所以能看到两个服务Socket通信正常,是因为你大概率在本地宿主机上手动启动了server.js,连的是容器暴露出来的3000端口服务。
另外你的配置还有两个明显问题:
docker-compose.yml中的mongo服务没有指定镜像,缺少image: mongo配置,正常情况下这个服务是无法启动的- 单容器跑多个常驻进程不符合Docker最佳实践,进程异常退出时很难被Docker感知到,也不方便做资源隔离和日志收集
排查解决步骤
快速修复(开发环境临时使用)
修改package.json的启动脚本,把&&换成&,让两个进程同时在后台启动:
"scripts": { "start": "nodemon index.js & nodemon server.js", "dev": "nodemon index.js & nodemon server.js" }
修改后先停掉你之前在宿主机上手动启动的server.js进程避免端口冲突,再执行docker-compose up --build启动,启动后可以通过以下方式验证:
- 执行
docker exec -it <你的test-app容器ID> ps aux,能看到两个nodemon/node进程分别对应index.js和server.js - 执行
docker exec -it <你的test-app容器ID> env,能看到MONGO_USER、MONGO_PASSWORD环境变量已正常注入 - 此时server.js运行在容器内部,和mongo服务在同一个Docker网络,可正常解析mongo域名、连接数据库
规范修复(推荐方案)
遵循Docker单容器单进程的最佳实践,把两个Node服务拆成docker-compose里的两个独立服务,修改后的docker-compose.yml示例:
version: "3" services: test-app-index: build: context: . args: NODE_ENV: development volumes: - .:/app - /app/node_modules environment: - NODE_ENV=development - MONGO_USER=test_admin - MONGO_PASSWORD=9293 command: npx nodemon index.js ports: - "3000:3000" test-app-server: build: context: . args: NODE_ENV: development volumes: - .:/app - /app/node_modules environment: - NODE_ENV=development - MONGO_USER=test_admin - MONGO_PASSWORD=9293 command: npx nodemon server.js ports: - "5000:5000" mongo: image: mongo # 补全缺失的镜像配置 environment: - MONGO_INITDB_ROOT_USERNAME=test_admin - MONGO_INITDB_ROOT_PASSWORD=9293 volumes: - mongo-data:/data/db # 增加数据卷持久化Mongo数据,避免容器重启数据丢失 mailhog: image: mailhog/mailhog logging: driver: 'none' ports: - 1025:1025 - 8025:8025 volumes: mongo-data:
这种方式下两个Node服务都在同一个Docker内部网络,都能正常读取环境变量、解析mongo服务域名,而且两个进程独立隔离,一个崩溃不会影响另一个,日志也可以单独查看。
内容的提问来源于stack exchange,提问作者IGentlich
相关产品推荐
相关产品推荐

