You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署MongoDB 7副本集后客户端无法连接完整集群问题

问题:Docker部署MongoDB三节点副本集后,客户端无法连接整个副本集

场景描述

在基于Arch的EndeavourOS 2023.05.28系统本地,使用Portainer Community 2.19.4管理Docker容器,部署了带用户名密码认证和密钥文件的MongoDB 7.0.5三节点副本集(1主2从),对应的docker-compose配置如下:

version: '3.8'

services:
  mongo1:
    image: mongo:7
    volumes:
      - /home/user/ducker/mongo-three-replica/rep1/data:/data/db
      - /home/user/ducker/mongo/rep.key:/opt/keyfile/mongo-keyfile
    environment:
      MONGO_INITDB_ROOT_USERNAME: your_username
      MONGO_INITDB_ROOT_PASSWORD: your_password
    command: "--replSet rs0 --keyFile /opt/keyfile/mongo-keyfile"
    ports:
      - "27017:27017"
    networks:
      - mongo-cluster

  mongo2:
    image: mongo:7
    volumes:
      - /home/user/ducker/mongo-three-replica/rep2/data:/data/db
      - /home/user/ducker/mongo/rep.key:/opt/keyfile/mongo-keyfile
    environment:
      MONGO_INITDB_ROOT_USERNAME: your_username
      MONGO_INITDB_ROOT_PASSWORD: your_password
    command: "--replSet rs0 --keyFile /opt/keyfile/mongo-keyfile"
    ports:
      - "27018:27017"
    networks:
      - mongo-cluster

  mongo3:
    image: mongo:7
    volumes:
      - /home/user/ducker/mongo-three-replica/rep3/data:/data/db
      - /home/user/ducker/mongo/rep.key:/opt/keyfile/mongo-keyfile
    environment:
      MONGO_INITDB_ROOT_USERNAME: your_username
      MONGO_INITDB_ROOT_PASSWORD: your_password
    command: "--replSet rs0 --keyFile /opt/keyfile/mongo-keyfile"
    ports:
      - "27019:27017"
    networks:
      - mongo-cluster

  rs-init:
    image: mongo:7
    depends_on:
      - mongo1
      - mongo2
      - mongo3
    networks:
      - mongo-cluster
    command: >
      bash -c "until mongosh --host mongo1:27017 --username your_username --password your_password --eval 'print(\"waiting for mongo1\")'; do sleep 2; done &&
             until mongosh --host mongo2:27017 --username your_username --password your_password --eval 'print(\"waiting for mongo2\")'; do sleep 2; done &&
             until mongosh --host mongo3:27017 --username your_username --password your_password --eval 'print(\"waiting for mongo3\")'; do sleep 2; done &&
             mongosh --host mongo1:27017 --username your_username --password your_password --eval '
             rs.initiate({
               _id: \"rs0\",
               members: [
                 { _id: 0, host: \"mongo1:27017\" },
                 { _id: 1, host: \"mongo2:27017\" },
                 { _id: 2, host: \"mongo3:27017\" }
               ]
             })'"
    restart: "no"

networks:
  mongo-cluster:
    driver: bridge

所有MongoDB容器处于同一bridge模式的mongo-cluster网络中,容器运行无报错,但客户端连接出现问题:

  • 使用连接字符串 mongodb://your_username:your_password@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0 时,提示 getaddrinfo ENOTFOUND mongo2(节点名随机变化);
  • 使用连接字符串 mongodb://your_username:your_password@localhost:27017/?replicaSet=rs0&authSource=admin&directConnection=true 可单节点连接,执行rs.status()显示副本集状态正常:
{
  set: 'rs0',
  date: 2024-01-19T04:37:25.215Z,
  myState: 1,
  term: Long('1'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1705639038, i: 1 }), t: Long('1') },
    lastCommittedWallTime: 2024-01-19T04:37:18.999Z,
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1705639038, i: 1 }), t: Long('1') },
    appliedOpTime: { ts: Timestamp({ t: 1705639038, i: 1 }), t: Long('1') },
    durableOpTime: { ts: Timestamp({ t: 1705639038, i: 1 }), t: Long('1') },
    lastAppliedWallTime: 2024-01-19T04:37:18.999Z,
    lastDurableWallTime: 2024-01-19T04:37:18.999Z
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1705639038, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: 2024-01-19T03:46:28.896Z,
    electionTerm: Long('1'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1705635978, i: 1 }), t: Long('-1') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1705635978, i: 1 }), t: Long('-1') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    numCatchUpOps: Long('0'),
    newTermStartDate: 2024-01-19T03:46:28.933Z,
    wMajorityWriteAvailabilityDate: 2024-01-19T03:46:29.458Z
  },
  members: [
    {
      _id: 0,
      name: 'mongo1:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 3068,
      optime: [Object],
      optimeDate: 2024-01-19T04:37:18.000Z,
      lastAppliedWallTime: 2024-01-19T04:37:18.999Z,
      lastDurableWallTime: 2024-01-19T04:37:18.999Z,
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1705635988, i: 1 }),
      electionDate: 2024-01-19T03:46:28.000Z,
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo2:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 3066,
      optime: [Object],
      optimeDurable: [Object],
      optimeDate: 2024-01-19T04:37:18.000Z,
      optimeDurableDate: 2024-01-19T04:37:18.000Z,
      lastAppliedWallTime: 2024-01-19T04:37:18.999Z,
      lastDurableWallTime: 2024-01-19T04:37:18.999Z,
      lastHeartbeat: 2024-01-19T04:37:24.921Z,
      lastHeartbeatRecv: 2024-01-19T04:37:23.916Z,
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo1:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'mongo3:27017',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 3066,
      optime: [Object],
      optimeDurable: [Object],
      optimeDate: 2024-01-19T04:37:18.000Z,
      optimeDurableDate: 2024-01-19T04:37:18.000Z,
      lastAppliedWallTime: 2024-01-19T04:37:18.999Z,
      lastDurableWallTime: 2024-01-19T04:37:18.999Z,
      lastHeartbeat: 2024-01-19T04:37:24.921Z,
      lastHeartbeatRecv: 2024-01-19T04:37:23.916Z,
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo1:27017',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1705639038, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('dQbmbbD3p1ac17YJFU75jyIg1mU=', 0),
      keyId: Long('7325650787340648454')
    }
  },
  operationTime: Timestamp({ t: 1705639038, i: 1 })
}

问题根源

副本集初始化时,节点名称配置的是Docker内部服务名(mongo1:27017、mongo2:27017、mongo3:27017),这些名称仅在Docker的mongo-cluster网络内可解析。当宿主机上的客户端连接到主节点后,主节点会返回副本集成员的内部地址,客户端无法解析这些地址,因此出现getaddrinfo ENOTFOUND错误。

修复方案

1. 重新配置副本集成员地址

通过单节点连接到主节点后,执行以下命令修改副本集配置,将成员地址替换为宿主机可访问的localhost加映射端口:

rs.reconfig({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})

注意:rs.reconfig()会触发副本集重新选举主节点,生产环境需在业务低峰期操作,避免影响服务。

2. 修改docker-compose初始化脚本(可选,用于后续部署)

如果需要后续部署自动使用正确的地址,修改rs-init服务中的初始化命令,将成员host改为宿主机可访问地址:

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})

3. 客户端连接字符串

修改完成后,使用以下连接字符串即可正常连接整个副本集:

mongodb://your_username:your_password@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0&authSource=admin

额外注意事项

  • 确保MongoDB容器内密钥文件/opt/keyfile/mongo-keyfile的权限为600,所属用户组为mongodb:mongodb,否则会导致副本集节点间通信失败。
  • 如果是远程客户端连接,需要将localhost替换为宿主机的公网IP或域名,并确保宿主机防火墙开放了27017、27018、27019端口。

内容的提问来源于stack exchange,提问作者Lost_In_Library

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:45:54