Docker单节点MongoDB副本集连接被拒问题排查求助
Docker单节点MongoDB副本集连接Mongoose被拒绝问题
问题现象
在Docker上搭建单节点MongoDB副本集后,Node.js应用通过Mongoose连接时被拒绝;但MongoDB作为独立实例运行时连接正常。
连接代码
mongoose.connect("mongodb://admin:secretpass@app_mongodb:27017/dbname?authSource=admin&replicaSet=rs0")
错误信息
/var/www/worker/node_modules/mongoose/lib/connection.js:824 const serverSelectionError = new ServerSelectionError(); ^ MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017
MongoDB日志
{"t":{"$date":"2023-01-27T10:22:46.410+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.18.0.10:41318","uuid":"2e1ccbc5-3162-4f64-80f3-8be580079ef6","connectionId":68,"connectionCount":11}} {"t":{"$date":"2023-01-27T10:22:46.417+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn68","msg":"client metadata","attr":{"remote":"172.18.0.10:41318","client":"conn68","doc":{"driver":{"name":"nodejs|Mongoose","version":"4.11.0"},"os":{"type":"Linux","name":"linux","architecture":"x64","version":"5.10.0-12-amd64"},"platform":"Node.js v19.5.0, LE (unified)","version":"4.11.0|6.7.5"}}} {"t":{"$date":"2023-01-27T10:22:46.425+00:00"},"s":"I", "c":"NETWORK", "id":22944, "ctx":"conn68","msg":"Connection ended","attr":{"remote":"172.18.0.10:41318","uuid":"2e1ccbc5-3162-4f64-80f3-8be580079ef6","connectionId":68,"connectionCount":10}}
docker-compose.yml配置
version: '3.8' services: mongodb: container_name: app_mongodb build: dockerfile: ./Dockerfile x-bake: no-cache: true environment: - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=secretpass volumes: - ./db:/data/db networks: - proxy restart: unless-stopped worker: container_name: app_worker image: "node:latest" command: "npm run dev" user: "node" working_dir: /var/www/worker environment: WAIT_HOSTS: app_mongodb:27017 volumes: - ./worker:/var/www/worker networks: - proxy links: - mongodb depends_on: - mongodb restart: unless-stopped networks: proxy: external: true
Dockerfile内容
FROM mongo # 创建副本集密钥文件 RUN echo "secretpasswordkey" > "/tmp/replica.key" RUN chmod 600 /tmp/replica.key RUN chown 999:999 /tmp/replica.key CMD ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/tmp/replica.key"]
手动执行的副本集初始化命令
rs.initiate({_id: 'rs0', members: [{_id:1, 'host':'127.0.0.1:27017'}]})
副本集状态(已成功初始化)
rs0 [direct: primary] admin> rs.status() { set: 'rs0', date: ISODate("2023-01-27T10:35:44.062Z"), myState: 1, term: Long("1"), syncSourceHost: '', syncSourceId: -1, heartbeatIntervalMillis: Long("2000"), majorityVoteCount: 1, writeMajorityCount: 1, votingMembersCount: 1, writableVotingMembersCount: 1, optimes: { lastCommittedOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") }, lastCommittedWallTime: ISODate("2023-01-27T10:35:39.161Z"), readConcernMajorityOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") }, appliedOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") }, durableOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") }, lastAppliedWallTime: ISODate("2023-01-27T10:35:39.161Z"), lastDurableWallTime: ISODate("2023-01-27T10:35:39.161Z") }, lastStableRecoveryTimestamp: Timestamp({ t: 1674815679, i: 1 }), electionCandidateMetrics: { lastElectionReason: 'electionTimeout', lastElectionDate: ISODate("2023-01-27T10:25:49.015Z"), electionTerm: Long("1"), lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1674815148, i: 1 }), t: Long("-1") }, lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1674815148, i: 1 }), t: Long("-1") }, numVotesNeeded: 1, priorityAtElection: 1, electionTimeoutMillis: Long("10000"), newTermStartDate: ISODate("2023-01-27T10:25:49.082Z"), wMajorityWriteAvailabilityDate: ISODate("2023-01-27T10:25:49.111Z") }, members: [ { _id: 1, name: '127.0.0.1:27017', health: 1, state: 1, stateStr: 'PRIMARY', uptime: 643, optime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") }, optimeDate: ISODate("2023-01-27T10:35:39.000Z"), lastAppliedWallTime: ISODate("2023-01-27T10:35:39.161Z"), lastDurableWallTime: ISODate("2023-01-27T10:35:39.161Z"), syncSourceHost: '', syncSourceId: -1, infoMessage: '', electionTime: Timestamp({ t: 1674815149, i: 1 }), electionDate: ISODate("2023-01-27T10:25:49.000Z"), configVersion: 1, configTerm: 1, self: true, lastHeartbeatMessage: '' } ], ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1674815739, i: 1 }), signature: { hash: Binary(Buffer.from("a211cfe3faa237bf8a30ccbc8ca929eea704f467", "hex"), 0), keyId: Long("7193276291800367109") } }, operationTime: Timestamp({ t: 1674815739, i: 1 }) }
问题原因
核心问题出在副本集成员的host配置:初始化副本集时用了127.0.0.1:27017作为节点地址,但在Docker环境中,这个地址仅代表MongoDB容器自身。当Node.js应用连接时,MongoDB会返回副本集的节点列表(即127.0.0.1:27017),导致应用尝试连接自己容器的127.0.0.1端口,自然被拒绝。
解决方案
1. 修改副本集初始化命令
将初始化命令中的host改为Docker容器名称app_mongodb(容器间可通过此域名相互访问):
rs.initiate({_id: 'rs0', members: [{_id:1, 'host':'app_mongodb:27017'}]})
2. 自动执行副本集初始化(无需手动操作)
MongoDB镜像会自动执行/docker-entrypoint-initdb.d/目录下的脚本,可将初始化逻辑集成到构建流程:
- 创建
init-replica.js文件:
rs.initiate({ _id: 'rs0', members: [ { _id: 1, host: 'app_mongodb:27017' } ] })
- 修改Dockerfile,添加COPY命令将脚本复制到容器内:
FROM mongo # 创建副本集密钥文件 RUN echo "secretpasswordkey" > "/tmp/replica.key" RUN chmod 600 /tmp/replica.key RUN chown 999:999 /tmp/replica.key # 复制副本集初始化脚本 COPY init-replica.js /docker-entrypoint-initdb.d/ CMD ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/tmp/replica.key"]
3. 验证连接配置
你的Mongoose连接字符串已正确使用app_mongodb作为地址,修改副本集配置后即可正常连接。
内容的提问来源于stack exchange,提问作者Finsky
相关产品推荐
相关产品推荐

