Docker部署Cassandra+Python操作遇NoHostAvailable/ConnectionRefusedError
修复Docker中Cassandra与Python应用连接拒绝问题
问题重现
本地通过Docker搭建Cassandra+Python环境,执行docker compose build和docker compose up后,Python应用抛出连接错误:
cassandra.cluster.NoHostAvailable: ('Unable to connect to any servers', {'172.23.0.2:9042': ConnectionRefusedError(111, "Tried connecting to [('172.23.0.2', 9042)]. Last error: Connection refused")})
原项目结构:
cassandra_study/ ├── script/ │ └── init-db.cql ├── app.py ├── Dockerfile └── docker-compose.yml
核心问题分析
- Cassandra初始化脚本未自动执行:仅挂载脚本目录,但未触发
init-db.cql执行,导致mykeyspace不存在。 - 健康检查配置过于激进:Cassandra启动需数十秒,1秒间隔+10次重试的配置会提前标记服务健康,Python应用过早发起连接。
- Cassandra网络配置缺失:默认配置下容器间通信可能受阻,需显式允许跨地址访问。
- Python连接无重试逻辑:即使健康检查通过,Cassandra可能仍在初始化,直接连接易失败。
修复步骤
1. 修改docker-compose.yml
调整Cassandra的环境变量、健康检查和初始化逻辑,确保服务完全就绪后再启动Python应用:
version: '3' services: python_app: build: context: . dockerfile: ./Dockerfile volumes: - ./:/app container_name: python_app-container depends_on: cassandra: condition: service_healthy cassandra: image: cassandra:latest volumes: - "./script:/scripts" - cassandra_data:/var/lib/cassandra # 持久化数据,避免重启丢失 ports: - 9042:9042 healthcheck: test: ["CMD-SHELL", "cqlsh -e 'DESCRIBE KEYSPACES;' || exit 1"] interval: 5s timeout: 10s retries: 20 # 延长重试次数,给Cassandra足够启动时间 environment: CASSANDRA_LISTEN_ADDRESS: 0.0.0.0 # 允许所有地址访问 CASSANDRA_RPC_ADDRESS: 0.0.0.0 CASSANDRA_START_RPC: 'true' container_name: cassandra-study-container command: > bash -c " /docker-entrypoint.sh cassandra -f & PID=$$! until cqlsh -e 'DESCRIBE KEYSPACES;' >/dev/null 2>&1; do echo 'Waiting for Cassandra to be ready...' sleep 2 done cqlsh -f /scripts/init-db.cql wait $$PID " volumes: cassandra_data: # 定义持久化卷
2. 修正init-db.cql
UUID类型字段不能直接用字符串'1',需使用合法UUID值或uuid()函数:
CREATE KEYSPACE IF NOT EXISTS mykeyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}; USE mykeyspace; CREATE TABLE IF NOT EXISTS mytable ( id UUID PRIMARY KEY, message TEXT ); -- 使用合法UUID值或uuid()函数插入数据 INSERT INTO mytable (id, message) VALUES (uuid(), 'hello i am the first'); INSERT INTO mytable (id, message) VALUES (uuid(), 'hello i am the second');
3. 优化app.py添加连接重试
添加重试逻辑,确保Cassandra完全就绪后再执行操作:
from cassandra.cluster import Cluster import time def connect_with_retry(): cluster = None session = None max_retries = 10 retry_count = 0 while retry_count < max_retries: try: cluster = Cluster(['cassandra'], port=9042) session = cluster.connect() # 确保keyspace存在 session.execute("CREATE KEYSPACE IF NOT EXISTS mykeyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}") session.set_keyspace('mykeyspace') print("Successfully connected to Cassandra") return cluster, session except Exception as e: print(f"Connection attempt {retry_count+1} failed: {e}") retry_count += 1 time.sleep(3) raise Exception("Failed to connect to Cassandra after max retries") cluster, session = connect_with_retry() try: # 插入新数据 session.execute("INSERT INTO mytable (id, message) VALUES (uuid(), 'ciao mondo sono il terzo')") session.execute("INSERT INTO mytable (id, message) VALUES (uuid(), 'ciao mondo sono il quarto')") # 查询并打印所有数据 result = session.execute("SELECT * FROM mytable") print("\nAll records in mytable:") for row in result: print(f"ID: {row.id}, Message: {row.message}") finally: cluster.shutdown()
4. 重新部署
执行以下命令重新构建并启动服务:
docker compose down -v # 清理旧容器和卷 docker compose build docker compose up
验证结果
启动后Python应用会输出所有插入的记录,包括init-db.cql中的2条和脚本新增的2条,说明连接和数据操作正常。
内容的提问来源于stack exchange,提问作者user23733163
相关产品推荐
相关产品推荐

