Spring Boot应用无法连接Docker中MongoDB副本集问题排查
问题:MacOS Docker部署MongoDB副本集,本地Spring Boot应用无法连接
问题描述
在MacOS(Apple M3 Pro)系统上通过Docker部署MongoDB副本集后,本地运行的Spring Boot应用无法连接到副本集,但本地通过nc命令能正常访问各节点。
错误日志
2024-11-19T21:46:50.470+03:00 DEBUG 57401 --- [}-mongod3:27017] org.mongodb.driver.connection : Connection pool ready for mongod3:27017 2024-11-19T21:46:50.470+03:00 INFO 57401 --- [}-mongod3:27017] org.mongodb.driver.cluster : Adding discovered server mongod2:27017 to client view of cluster 2024-11-19T21:46:50.470+03:00 DEBUG 57401 --- [199052-thread-1] org.mongodb.driver.connection : Connection created: address=mongod3:27017, driver-generated ID=298664 2024-11-19T21:46:50.470+03:00 DEBUG 57401 --- [}-mongod3:27017] org.mongodb.driver.connection : Connection pool created for mongod2:27017 using options maxIdleTimeMS=0, minPoolSize=5, maxPoolSize=100, maxConnecting=2, waitQueueTimeoutMS=120000 2024-11-19T21:46:50.471+03:00 INFO 57401 --- [}-mongod3:27017] org.mongodb.driver.cluster : Canonical address mongod1:27017 does not match server address. Removing mongod3:27017 from client view of cluster 2024-11-19T21:46:50.471+03:00 DEBUG 57401 --- [}-mongod3:27017] org.mongodb.driver.connection : Connection pool closed for mongod3:27017 2024-11-19T21:46:50.471+03:00 DEBUG 57401 --- [199052-thread-1] org.mongodb.driver.connection : Connection closed: address=mongod3:27017, driver-generated ID=298664. Reason: An error occurred while using the connection. Error: There was a socket exception raised by this connection 2024-11-19T21:46:50.469+03:00 INFO 57401 --- [}-mongod2:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server mongod2:27017
本地访问测试结果
nc -zv mongod1 27017 Connection to mongod1 port 27017 [tcp/*] succeeded! nc -zv mongod2 27018 Connection to mongod2 port 27018 [tcp/*] succeeded! nc -zv mongod3 27019 Connection to mongod3 port 27019 [tcp/*] succeeded!
Docker配置
version: '3.8' services: mongod1: image: mongo:latest container_name: mongod1 hostname: mongod1 ports: - "27017:27017" environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: root MONGO_INITDB_REPLICA_SET_NAME: rs0 volumes: - ./mongo-keyfile:/data/replica.key:rw - mongod1-data:/data/db command: mongod --bind_ip_all --replSet rs0 --keyFile /data/replica.key --auth networks: - mongo-net mongod2: image: mongo:latest container_name: mongod2 hostname: mongod2 ports: - "27018:27017" environment: MONGO_INITDB_REPLICA_SET_NAME: rs0 volumes: - ./mongo-keyfile:/data/replica.key:rw - mongod2-data:/data/db command: mongod --bind_ip_all --replSet rs0 --keyFile /data/replica.key --auth networks: - mongo-net mongod3: image: mongo:latest container_name: mongod3 hostname: mongod3 ports: - "27019:27017" environment: MONGO_INITDB_REPLICA_SET_NAME: rs0 volumes: - ./mongo-keyfile:/data/replica.key:rw - mongod3-data:/data/db command: mongod --bind_ip_all --replSet rs0 --keyFile /data/replica.key --auth networks: - mongo-net mongo-init: image: mongo:latest container_name: mongo-init depends_on: - mongod1 - mongod2 - mongod3 volumes: - ./init-replica.sh:/init-replica.sh:rw - ./mongo-keyfile:/data/replica.key:rw entrypoint: ["bash", "/init-replica.sh"] networks: - mongo-net mongo-express: image: mongo-express:latest container_name: mongo-express environment: ME_CONFIG_MONGODB_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: root ME_CONFIG_MONGODB_URL: "mongodb://root:root@mongod1:27017,mongod2:27017,mongod3:27017/admin?replicaSet=rs0" ME_CONFIG_MONGODB_ENABLE_ADMIN: "true" ME_CONFIG_SITE_USERNAME: admin ME_CONFIG_SITE_PASSWORD: pass ports: - "8081:8081" depends_on: - mongo-init networks: - mongo-net volumes: mongod1-data: mongod2-data: mongod3-data: networks: mongo-net: driver: bridge
Spring配置类
@Configuration @RequiredArgsConstructor @EnableConfigurationProperties(MongoProperties.class) @EnableReactiveMongoRepositories(basePackages = "com.example.demo.repository") public class MongoConfig extends AbstractReactiveMongoConfiguration { private final MongoProperties mongoProperties; @Override protected String getDatabaseName() { return mongoProperties.getDatabase(); } @Override public com.mongodb.reactivestreams.client.MongoClient reactiveMongoClient() { String mongoUri = mongoProperties.getUri(); return com.mongodb.reactivestreams.client.MongoClients.create(mongoUri); } @Bean public ReactiveMongoTemplate reactiveMongoTemplate() { return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName()); } @Bean public ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory factory) { return new ReactiveMongoTransactionManager(factory); } }
Spring配置文件
spring: autoconfigure: exclude: - org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration data: mongodb: database: accounts username: root password: root authentication-database: admin uri: mongodb://root:root@mongod1:27017,mongod2:27018,mongod3:27019/accounts?authSource=admin&replicaSet=rs0&maxPoolSize=100&minPoolSize=5&retryWrites=true&w=majority&readPreference=primaryPreferred
问题原因与解决方法
核心原因
MongoDB副本集初始化时使用的是Docker容器内部的主机名(mongod1/mongod2/mongod3)和内部端口27017。当本地Spring Boot应用连接到副本集后,Mongo驱动会从副本集获取节点列表,但返回的是容器内部的地址(比如mongod2:27017)。本地客户端尝试连接这个地址时,虽然mongod2能解析到本地IP,但端口27017对应的是mongod1的映射端口,自然无法连接到mongod2,导致连接失败。
解决步骤
修改副本集初始化脚本
编辑init-replica.sh,将副本集的节点地址替换为本地可访问的地址(localhost或主机IP)加上映射后的端口:#!/bin/bash sleep 10 mongosh --host mongod1:27017 -u root -p root --eval " rs.initiate({ _id: 'rs0', members: [ { _id: 0, host: 'localhost:27017' }, { _id: 1, host: 'localhost:27018' }, { _id: 2, host: 'localhost:27019' } ] }) rs.status()"更新Spring配置文件的Mongo URI
将URI中的节点地址改为localhost对应的映射端口,确保客户端能直接访问:spring: data: mongodb: uri: mongodb://root:root@localhost:27017,localhost:27018,localhost:27019/accounts?authSource=admin&replicaSet=rs0&maxPoolSize=100&minPoolSize=5&retryWrites=true&w=majority&readPreference=primaryPreferred重启服务
- 停止并删除现有Mongo容器:
docker-compose down -v - 重新部署:
docker-compose up -d - 重启Spring Boot应用
- 停止并删除现有Mongo容器:
补充说明
如果你的/etc/hosts文件中已经配置了mongod1/mongod2/mongod3指向127.0.0.1,也可以将URI中的localhost替换为这些主机名,但需要确保副本集初始化时也使用对应的主机名+映射端口,保持一致。
内容的提问来源于stack exchange,提问作者skyho
相关产品推荐
相关产品推荐

