容器化Spring Boot应用连接Docker MongoDB出现Socket打开异常
问题描述
我有一个Spring Boot应用(test-service):
- 容器外运行时,可正常连接非容器化和容器化的MongoDB实例;
- 容器化运行该应用时,抛出
MongoSocketOpenException异常; - 进入test-service容器后能ping通容器化的MongoDB,但连接失败;
- 已排查MongoDB用户权限(添加额外角色、测试test用户),问题仍未解决。
堆栈跟踪
test-service | 2023-04-15 01:31:14.099 INFO 1 --- [}-mongodb:27018] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server mongodb:27018 test-service | test-service | com.mongodb.MongoSocketOpenException: Exception opening socket test-service | at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:70) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:180) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:193) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:157) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na] test-service | Caused by: java.net.ConnectException: Connection refused: mongodb:27018 test-service | at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na] test-service | at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na] test-service | at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:542) ~[na:na] test-service | at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:597) ~[na:na] test-service | at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na] test-service | at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na] test-service | at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:107) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at com.mongodb.internal.connection.SocketStream.initializeSocket(SocketStream.java:79) ~[mongodb-driver-core-4.6.1.jar:na] test-service | at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:65) ~[mongodb-driver-core-4.6.1.jar:na] test-service | ... 4 common frames omitted
docker-compose.yml
version: "3" services: mongodb: image: mongo:6.0.5 container_name: mongodb volumes: - mongodb:/data/db ports: - "27018:27017" environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: admin MONGO_INITDB_DATABASE: test-service platform: linux/arm64 test-service: image: test-service:0.1.0 container_name: test-service volumes: - $HOME/config/keystore:/var/keystore ports: - 8083:8083 environment: MONGO_HOST: mongodb MONGO_PORT: 27018 MONGO_USER: admin MONGO_PASSWORD: admin MONGO_AUTH_DB: admin KEYSTORE_PATH: /var/keystore/dev-env-cert.p12 platform: linux/arm64 depends_on: - mongodb volumes: mongodb: {}
application.properties
mongodb.host=${MONGO_HOST:localhost} mongodb.port=${MONGO_PORT:27017} mongodb.database=test-service mongodb.authentication-database=${MONGO_AUTH_DB:admin} mongodb.username=${MONGO_USER:admin} mongodb.password=${MONGO_PASSWORD:admin}
Mongo配置(Java代码)
@Configuration public class MongoConfig extends AbstractMongoClientConfiguration { @Value("${mongodb.host}") private String dbHost; @Value("${mongodb.port}") private String dbPort; @Value("${mongodb.authentication-database}") private String dbAuthDb; @Value("${mongodb.username}") private String dbUsername; @Value("${mongodb.password}") private String dbPassword; @Value("${mongodb.database}") private String dbName; @Override protected String getDatabaseName() { return dbName; } @Override protected String getMappingBasePackage() { return "com.test.model"; } @Override public MongoClient mongoClient() { MongoClientSettings settings = MongoClientSettings .builder() .applyConnectionString(new ConnectionString("mongodb://" + dbHost + ":" + dbPort + "/" + dbName)) .credential(MongoCredential.createScramSha256Credential(dbUsername, dbAuthDb, dbPassword.toCharArray())) .applicationName(dbName) .build(); MongoClient client = MongoClients.create(settings); return client; } }
补充说明
已检查容器的admin数据库,尝试添加额外角色并使用test用户测试,但问题仍未解决:
admin> db.getUsers() { users: [ { _id: 'admin.admin', userId: new UUID("8730bf38-301c-4123-a8a3-1c651d7b1e4e"), user: 'admin', db: 'admin', roles: [ { role: 'dbOwner', db: 'test-service' }, { role: 'root', db: 'admin' } ], mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ] }, { _id: 'admin.test', userId: new UUID("fb16d8e3-537b-4f67-a6fc-2b22faf6f242"), user: 'test', db: 'admin', roles: [ { role: 'dbOwner', db: 'test-service' } ], mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ] } ], ok: 1 }
核心问题与修复方案
核心错误
Docker Compose网络中,容器间直接通信需使用MongoDB容器内部的端口(27017),而非宿主机的映射端口(27018)。当前配置MONGO_PORT=27018是错误的,该端口仅对宿主机开放,容器内部无法通过此端口访问MongoDB容器。
修复步骤
- 修改
docker-compose.yml中test-service的环境变量:environment: MONGO_HOST: mongodb MONGO_PORT: 27017 # 改为MongoDB容器内部的默认端口 MONGO_USER: admin MONGO_PASSWORD: admin MONGO_AUTH_DB: admin KEYSTORE_PATH: /var/keystore/dev-env-cert.p12 - 重启服务:
docker-compose down && docker-compose up -d
额外验证(可选)
- 进入test-service容器,用MongoShell连接验证:
docker exec -it test-service bash # 若容器内无MongoShell,执行以下安装命令 apt update && apt install -y mongodb-clients # 连接MongoDB容器 mongosh mongodb:27017/test-service -u admin -p admin --authenticationDatabase admin - 检查MongoDB容器启动状态:
确认日志中出现docker logs mongodbWaiting for connections字样,说明服务就绪。
为什么ping通但连接失败?
ping基于ICMP协议,仅验证主机可达性,不校验端口是否开放;- 你尝试访问的27018端口在MongoDB容器内部并未开放,因此连接被拒绝。
内容的提问来源于stack exchange,提问作者Molasses
相关产品推荐
相关产品推荐

