如何正确将Mongo副本集容器与Node.js应用容器连接?
问题描述
本地执行npm run start,使用连接字符串mongodb://localhost:27017/databaseDev?authSource=admin时能正常连接MongoDB,但通过Docker Compose部署的相同应用,使用mongodb://mongo:27017/databaseDev?authSource=admin却无法连接MongoDB。
提供的配置文件
docker-compose.yml
version: '3.5' services: mongo: container_name: mongo image: mongo:4.4.15 volumes: - ./mongodb/data:/data/db - ./mongodb/init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh ports: - 27017:27017 environment: MONGO_INITDB_DATABASE: 'databaseDev' command: ["--replSet", "rs0", "--bind_ip_all"] api: container_name: api build: context: ./ dockerfile: Dockerfile volumes: - ./:/var/app - /var/app/node_modules ports: - 3010:3010 environment: PORT: 3010 NODE_ENV: 'development' DB_HOST: 'mongo' DB_PORT: 27017 DB_NAME: 'databaseDev' depends_on: - mongo command: ['node', 'dist/main']
init-mongo.sh
mongo -- "$MONGO_INITDB_DATABASE" <<EOF rs.initiate(); rs.status(); EOF
Dockerfile
FROM node:16.15.1 as build WORKDIR /var/app COPY . . RUN npm ci CMD ["node", "dist/main"]
问题排查与解决方法
1. Docker Compose配置缩进错误
你的docker-compose.yml中depends_on的缩进位置错误,它应该属于api服务的配置项,而非与services同级。错误的缩进会导致depends_on不生效,api容器可能在MongoDB容器完全启动前就开始运行。
修正后的api服务配置:
api: container_name: api build: context: ./ dockerfile: Dockerfile volumes: - ./:/var/app - /var/app/node_modules ports: - 3010:3010 environment: PORT: 3010 NODE_ENV: 'development' DB_HOST: 'mongo' DB_PORT: 27017 DB_NAME: 'databaseDev' depends_on: - mongo command: ['node', 'dist/main']
2. MongoDB副本集初始化不完整
depends_on仅保证MongoDB容器启动,不保证副本集初始化完成。Node应用启动时,MongoDB可能还在执行rs.initiate(),导致连接失败。
解决方法:
- 在Node应用代码中添加连接重试逻辑,捕获连接错误并重试;
- 使用等待脚本(如
wait-for-it.sh)在启动Node应用前等待MongoDB副本集就绪,例如修改api服务的command:command: ["./wait-for-it.sh", "mongo:27017", "--", "node", "dist/main"]
3. 副本集初始化配置缺失主机名
当前init-mongo.sh中的rs.initiate()未指定主机名,默认会使用MongoDB容器的内部主机名(可能是容器ID),而Node应用连接的是服务名mongo,导致驱动无法识别副本集成员。
修改init-mongo.sh,明确指定副本集成员为mongo:27017:
mongo -- "$MONGO_INITDB_DATABASE" <<EOF rs.initiate({ _id: "rs0", members: [ { _id: 0, host: "mongo:27017" } ] }); rs.status(); EOF
4. 连接字符串未指定副本集名称
因为MongoDB以副本集模式启动(--replSet rs0),但连接字符串中未声明副本集名称,Node驱动无法正确处理副本集连接。
修改连接字符串为:
mongodb://mongo:27017/databaseDev?authSource=admin&replicaSet=rs0
5. 容器网络连通性验证
如果上述方法无效,可进入api容器验证是否能解析mongo主机名:
docker exec -it api ping mongo
如果无法ping通,检查Docker网络配置,确保两个服务处于同一个默认网络中(Docker Compose默认会为所有服务创建并加入同一个网络)。
内容的提问来源于stack exchange,提问作者Moti

