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

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,导致连接失败。

解决步骤

  1. 修改副本集初始化脚本
    编辑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()"
    
  2. 更新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
    
  3. 重启服务

    • 停止并删除现有Mongo容器:docker-compose down -v
    • 重新部署:docker-compose up -d
    • 重启Spring Boot应用

补充说明

如果你的/etc/hosts文件中已经配置了mongod1/mongod2/mongod3指向127.0.0.1,也可以将URI中的localhost替换为这些主机名,但需要确保副本集初始化时也使用对应的主机名+映射端口,保持一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:44:50