Docker Compose中Spring应用无法连接Cassandra求助
问题:Spring应用通过Docker Compose连接Cassandra失败
问题背景
Spring应用依赖Cassandra数据库,将二者配置在同一个Docker Compose文件中。本地单独用Docker运行时一切正常,但通过Compose部署时,应用始终出现连接错误。
Docker Compose配置
version: "3.9" services: myapplication: image: eclipse-temurin:17.0.7_7-jre working_dir: /root/app restart: on-failure command: sh -c "java -jar -Dspring.profiles.active=docker /root/app/app.jar" depends_on: - db volumes: - jar:/root/app/ - ./logs:/root/app/logs db: image: cassandra:5.0 restart: always container_name: cassandra environment: CASSANDRA_CLUSTER_NAME: app ports: - "9042:9042" - "9160:9160" - "7199:7199" volumes: - cas_data:/var/lib/cassandra volumes: cas_data: driver: local networks: default: name: my-application
Spring应用配置
spring.cassandra.schema-action=CREATE_IF_NOT_EXISTS #spring.cassandra.request.timeout=10s #spring.cassandra.connection.connect-timeout=10s #spring.cassandra.connection.init-query-timeout=20s #spring.cassandra.keyspace-name=app #spring.data.cassandra.port=9042 spring.data.cassandra.contact-points=cassandra spring.cassandra.local-datacenter=datacenter1
排查测试
在应用容器内通过nc命令可正常连接cassandra服务的9042端口:
# nc -zv cassandra 9042 Connection to cassandra (192.xxx.xxx.x) 9042 port [tcp/*] succeeded!
错误日志
应用抛出连接错误:
Caused by: com.datastax.oss.driver.api.core.AllNodesFailedException: Could not reach any contact point, make sure you've provided valid addresses (showing first 1 nodes, use getAllErrors() for more): Node(endPoint=/127.0.0.1:9042, hostId=null, hashCode=7b503e49): [com.datastax.oss.driver.api.core.connection.ConnectionInitException: [s0|control|connecting...] Protocol initialization request, step 1 (OPTIONS): failed to send request (io.netty.channel.StacklessClosedChannelException)] at com.datastax.oss.driver.api.core.AllNodesFailedException.copy(AllNodesFailedException.java:141) ~[java-driver-core-4.15.0.jar!/:na]
详细错误栈:
Suppressed: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:9042 Caused by: java.net.ConnectException: Connection refused at java.base/sun.nio.ch.Net.pollConnect(Native Method) at java.base/sun.nio.ch.Net.pollConnectNow(Unknown Source) at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source) at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:337) at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Unknown Source) Caused by: io.netty.channel.StacklessClosedChannelException: null at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0()(Unknown Source)
原因分析
- 配置未生效:错误日志显示应用尝试连接
127.0.0.1:9042,而非配置中的cassandra主机名,说明spring.data.cassandra.contact-points=cassandra配置未被正确加载。可能是Docker Profile配置文件未正确命名/放置,或Spring Boot版本导致属性前缀不兼容(比如Spring Boot 3.x推荐使用spring.cassandra.*前缀,而非spring.data.cassandra.*)。 - Cassandra未就绪:Compose的
depends_on仅保证容器启动顺序,不保证Cassandra服务完全初始化完成,Spring应用启动时Cassandra可能还未准备好接受连接。
解决方案
1. 确保配置正确加载
- 确认Docker Profile的配置文件命名为
application-docker.properties,且放置在应用的classpath路径下。 - 根据Spring Boot版本统一配置前缀:Spring Boot 3.x建议使用
spring.cassandra.*前缀,修改配置如下:spring.cassandra.schema-action=CREATE_IF_NOT_EXISTS spring.cassandra.request.timeout=10s spring.cassandra.connection.connect-timeout=10s spring.cassandra.connection.init-query-timeout=20s spring.cassandra.keyspace-name=app spring.cassandra.port=9042 spring.cassandra.contact-points=cassandra spring.cassandra.local-datacenter=datacenter1
2. 等待Cassandra服务就绪后启动应用
方式一:添加启动前等待脚本
修改Compose中myapplication的command,增加循环检测Cassandra端口的逻辑:
command: sh -c "until nc -zv cassandra 9042; do echo waiting for cassandra; sleep 2; done; java -jar -Dspring.profiles.active=docker /root/app/app.jar"
方式二:使用Compose健康检查
在db服务中添加健康检查,确保Cassandra服务就绪后再启动应用:
db: image: cassandra:5.0 restart: always container_name: cassandra environment: CASSANDRA_CLUSTER_NAME: app ports: - "9042:9042" - "9160:9160" - "7199:7199" volumes: - cas_data:/var/lib/cassandra healthcheck: test: ["CMD", "cqlsh", "-u", "cassandra", "-p", "cassandra", "-e", "DESCRIBE KEYSPACES;"] interval: 10s timeout: 5s retries: 5
同时修改myapplication的depends_on:
depends_on: db: condition: service_healthy
3. 配置Cassandra广播地址
在db服务的环境变量中添加广播地址配置,确保Cassandra返回正确的容器主机名给客户端:
environment: CASSANDRA_CLUSTER_NAME: app CASSANDRA_LISTEN_ADDRESS: cassandra CASSANDRA_BROADCAST_ADDRESS: cassandra
内容的提问来源于stack exchange,提问作者Akash Jain
相关产品推荐
相关产品推荐

