无法通过Compass连接本地Docker部署的MongoDB副本集集群
通过如下docker-compose.yml配置定义MongoDB Docker集群:
version: "3" services: mongo1: hostname: mongo1 container_name: mongo1 image: mongo:5 volumes: - ${PWD}/data/db/mongo1:/data/db expose: - 27017 ports: - "27011:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ] mongo2: hostname: mongo2 container_name: mongo2 image: mongo:5 volumes: - ${PWD}/data/db/mongo2:/data/db expose: - 27017 ports: - "27012:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ] mongo3: hostname: mongo3 container_name: mongo3 image: mongo:5 volumes: - ${PWD}/data/db/mongo3:/data/db expose: - 27017 ports: - "27013:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
执行命令启动集群:
mkdir data docker-compose up -d
执行命令初始化副本集:
docker exec -it mongo1 mongosh --eval "rs.initiate({ _id: \"rs0\", members: [ {_id: 0, host: \"mongo1\"}, {_id: 1, host: \"mongo2\"}, {_id: 2, host: \"mongo3\"} ] })"
使用单节点无副本集参数的连接串可以正常连接:
mongosh "mongodb://localhost:27011/my_db"
但连接串指定replicaSet参数时连接失败,提示无法解析主机mongo1,报错信息如下:
$ mongosh "mongodb://localhost:27011/my_db?replicaSet=rs0" Current Mongosh Log ID: 62b54fa6573be03f584017b8 Connecting to: mongodb://localhost:27011/my_db?replicaSet=rs0&serverSelectionTimeoutMS=2000&appName=mongosh+1.5.0 MongoServerSelectionError: getaddrinfo EAI_AGAIN mongo1
使用多节点连接串mongodb://localhost:27011,localhost:27012,localhost:27013/my_db连接也会触发相同错误,且可正常在mongosh中使用的单节点连接串,无法在MongoDB Compass中成功连接集群。已知添加network_mode: "host"配置可以解决主机发现问题,但不希望采用该方案。
MongoDB驱动在连接串携带replicaSet参数、或传入多个节点地址时,会先和初始连接的节点建立通信,拉取副本集内置的所有成员列表用于自动故障切换。当前副本集初始化时写入的成员地址是Docker内部网桥的主机名mongo1/mongo2/mongo3,宿主机没有对应域名解析记录,无法访问这些内部地址,因此抛出主机解析失败错误。MongoDB Compass默认会启用副本集发现逻辑,哪怕只填写单节点地址也会触发该问题。
无需使用host网络模式,可根据使用场景选择以下方案:
方案1:配置宿主机hosts映射+调整副本集成员端口(无侵入改网络配置)
- 编辑宿主机hosts文件,添加容器主机名的本地映射:
Linux/macOS系统hosts路径为
/etc/hosts
Windows系统hosts路径为C:\Windows\System32\drivers\etc\hosts
在文件末尾追加如下内容:127.0.0.1 mongo1 mongo2 mongo3 - 进入mongo1容器的mongosh终端:
docker exec -it mongo1 mongosh - 执行命令修改副本集成员地址,替换为宿主机映射的端口:
如果执行reconfig时报配置版本或权限错误,可替换为cfg = rs.conf() cfg.members[0].host = "mongo1:27011" cfg.members[1].host = "mongo2:27012" cfg.members[2].host = "mongo3:27013" rs.reconfig(cfg)rs.reconfig(cfg, {force: true})强制执行,配置会在10秒内同步到所有节点。 - 配置完成后即可用标准副本集连接串正常访问,Compass也可正常连接:
容器内部通信依然走Docker内网的27017端口,宿主机访问走映射后的端口,互不干扰。mongodb://mongo1:27011,mongo2:27012,mongo3:27013/my_db?replicaSet=rs0
方案2:自定义Docker固定IP网络(保留副本集默认27017端口配置)
如果不想修改副本集成员的端口配置,可以给Mongo集群分配固定的自定义网络IP,直接让宿主机通过固定IP访问容器:
- 修改
docker-compose.yml,新增自定义网络配置并给每个容器分配固定IP:
version: "3" networks: mongo-cluster: ipam: config: - subnet: 172.20.0.0/16 services: mongo1: hostname: mongo1 container_name: mongo1 image: mongo:5 volumes: - ${PWD}/data/db/mongo1:/data/db ports: - "27011:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ] networks: mongo-cluster: ipv4_address: 172.20.0.2 mongo2: hostname: mongo2 container_name: mongo2 image: mongo:5 volumes: - ${PWD}/data/db/mongo2:/data/db ports: - "27012:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ] networks: mongo-cluster: ipv4_address: 172.20.0.3 mongo3: hostname: mongo3 container_name: mongo3 image: mongo:5 volumes: - ${PWD}/data/db/mongo3:/data/db ports: - "27013:27017" restart: always entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ] networks: mongo-cluster: ipv4_address: 172.20.0.4
- 重启集群,备份原有数据后重新初始化副本集,成员地址保持默认的
mongo1:27017/mongo2:27017/mongo3:27017即可。 - 修改宿主机hosts文件,追加IP映射:
172.20.0.2 mongo1 172.20.0.3 mongo2 172.20.0.4 mongo3
- 后续可直接用默认端口的副本集连接串访问:
mongodb://mongo1:27017,mongo2:27017,mongo3:27017/my_db?replicaSet=rs0
临时调试方案
如果只是本地临时调试,不需要副本集故障转移能力,可以在连接串末尾添加directConnection=true参数,强制驱动以单节点模式连接,不会触发副本集节点发现逻辑,无需修改任何配置:
mongodb://localhost:27011/my_db?directConnection=true
注意:该模式下连接的节点宕机后不会自动切换到其他节点,仅适合临时调试使用。
内容的提问来源于stack exchange,提问作者abhinavkulkarni

