Docker容器外访问ScyllaDB集群遇NoHostAvailable错误求助
本地Docker容器运行ScyllaDB集群,容器外的FastAPI应用访问集群时触发错误:cassandra.cluster.NoHostAvailable: ('Unable to connect to any servers')
集群状态信息
Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns Host ID Rack UN 172.17.0.2 776 KB 256 ? ad698c75-a465-4deb-a92c-0b667e82a84f rack1 Note: Non-system keyspaces don't have the same replication settings, effective ownership information is meaningless
Cluster Information: Name: Test Cluster Snitch: org.apache.cassandra.locator.SimpleSnitch DynamicEndPointSnitch: disabled Partitioner: org.apache.cassandra.dht.Murmur3Partitioner Schema versions: 443048b2-c1fe-395e-accd-5ae9b6828464: [172.17.0.2]
可正常访问的场景
使用cqlsh通过9042端口连接集群无问题:
Connected to at 172.17.0.2:9042. [cqlsh 5.0.1 | Cassandra 3.0.8 | CQL spec 3.3.1 | Native protocol v4]
报错代码及信息
容器外FastAPI应用执行以下代码时报错:
from cassandra.cluster import Cluster cluster = Cluster(['172.17.0.2']) session = cluster.connect('Test Cluster')
错误信息:
raise NoHostAvailable("Unable to connect to any servers", errors) cassandra.cluster.NoHostAvailable: ('Unable to connect to any servers', {'172.17.0.2:9042': OSError(51, "Tried connecting to [('172.17.0.2', 9042)]. Last error: Network is unreachable")})
核心原因
172.17.0.2是Docker容器内部的桥接网络IP,容器外的主机无法直接访问这个内部IP,这是导致「网络不可达」错误的根本原因。你用cqlsh能正常连接,大概率是因为cqlsh运行在容器内部,或者你的主机网络与Docker桥接网络直接打通,但FastAPI所在环境不在这个网络范围内。
具体解决步骤
步骤1:重新启动ScyllaDB容器,配置端口映射与监听地址
启动容器时,必须将容器的9042端口映射到主机端口,同时让ScyllaDB监听所有地址(0.0.0.0),确保外部能访问。示例启动命令:docker run -d \ --name scylla-node1 \ -p 9042:9042 \ -e SCYLLA_LISTEN_ADDRESS=0.0.0.0 \ -e SCYLLA_RPC_ADDRESS=0.0.0.0 \ scylladb/scylla其中
-p 9042:9042实现端口映射,SCYLLA_LISTEN_ADDRESS和SCYLLA_RPC_ADDRESS设置为0.0.0.0,允许ScyllaDB接受外部连接请求。步骤2:修正FastAPI的连接代码
将连接目标IP改为主机的IP(如果FastAPI在主机本地运行,用localhost即可),端口使用映射后的9042。另外注意:cluster.connect()的参数是keyspace名称,不是集群名称「Test Cluster」,这是常见误区。修正后的代码:from cassandra.cluster import Cluster # FastAPI在主机本地运行时用localhost cluster = Cluster(['localhost'], port=9042) # FastAPI在局域网其他机器时,替换为主机的局域网IP,比如192.168.1.100 # cluster = Cluster(['192.168.1.100'], port=9042) # 替换为实际的keyspace名称,而非集群名称 session = cluster.connect('your_keyspace_name')步骤3:验证网络连通性
在FastAPI所在环境执行以下命令,确认端口连通:# 用telnet验证 telnet localhost 9042 # 或用nc验证 nc -zv localhost 9042如果不通,检查Docker端口映射是否生效,以及主机防火墙是否放行9042端口。
内容的提问来源于stack exchange,提问作者john meiners

