Python经堡垒机连接远程MongoDB集群遇ServerSelectionTimeoutError求助
解决Python通过SSH堡垒机连接MongoDB副本集的ServerSelectionTimeoutError问题
1. 修正SSH隧道的私钥密码参数
你的代码中错误地将私钥的passphrase传给了ssh_password参数,该参数用于密码登录堡垒机,而加密私钥的密码需要使用ssh_private_key_password参数:
server = SSHTunnelForwarder( ssh_address_or_host=(bastion_adress, 22), ssh_username=username, ssh_pkey=r'\private_key_adress.pem', # 替换ssh_password为ssh_private_key_password ssh_private_key_password=pp_pkey, remote_bind_address=('mongo_db_server_adress', 27017), local_bind_address=('127.0.0.1', 27018) )
2. 处理MongoDB副本集的节点访问问题
你使用Compass的srv连接字符串能成功,说明目标是MongoDB副本集。副本集的特性是:客户端连接后,MongoDB会返回所有副本集节点的私有网络地址,客户端会直接尝试连接这些地址,但本地无法访问私有网络,这是导致超时的核心原因。
方案A:强制直连单个节点(快速临时解决)
在MongoClient中添加directConnection=True参数,强制只连接隧道转发的节点,适合临时测试:
db = pymongo.MongoClient( connection_str, username=username, password=pp_mongouser, tls=True, # 强制直连指定节点 directConnection=True, # 若使用自签名证书,需添加该参数(根据实际情况调整) tlsAllowInvalidCertificates=True )["db_name"]
方案B:完整支持副本集(推荐)
要完整支持副本集的故障转移,需让本地能访问所有副本集节点:
- 通过Compass连接后查看副本集配置,获取所有节点的域名/IP
- 在本地
hosts文件中,将每个副本集节点的域名映射到127.0.0.1 - 为每个节点创建独立的SSH隧道,转发到本地不同端口:
# 示例:假设副本集有3个节点 servers = [] # 节点1隧道 servers.append(SSHTunnelForwarder( (bastion_adress, 22), ssh_username=username, ssh_pkey=r'\private_key_adress.pem', ssh_private_key_password=pp_pkey, remote_bind_address=('mongo-node1.example.com', 27017), local_bind_address=('127.0.0.1', 27018) )) # 节点2隧道 servers.append(SSHTunnelForwarder( (bastion_adress, 22), ssh_username=username, ssh_pkey=r'\private_key_adress.pem', ssh_private_key_password=pp_pkey, remote_bind_address=('mongo-node2.example.com', 27017), local_bind_address=('127.0.0.1', 27019) )) # 节点3隧道 servers.append(SSHTunnelForwarder( (bastion_adress, 22), ssh_username=username, ssh_pkey=r'\private_key_adress.pem', ssh_private_key_password=pp_pkey, remote_bind_address=('mongo-node3.example.com', 27017), local_bind_address=('127.0.0.1', 27020) )) # 启动所有隧道 for s in servers: s.start() - 构造包含所有本地转发地址的连接字符串,并指定副本集名称:
connection_str = 'mongodb://127.0.0.1:27018,127.0.0.1:27019,127.0.0.1:27020' db = pymongo.MongoClient( connection_str, username=username, password=pp_mongouser, tls=True, replicaSet='replicaset', # 替换为你的副本集名称 # 自签名证书需添加 tlsAllowInvalidCertificates=True )["db_name"] - 操作完成后停止所有隧道:
for s in servers: s.stop()
3. 其他排查点
- 确认堡垒机私钥路径正确(Windows路径需用
\\或原始字符串r'C:\path\to\key.pem') - 用
telnet 127.0.0.1 27018测试本地端口是否正常连通 - 检查MongoDB用户权限:确保用户拥有
listCollections权限 - 若使用MongoDB Atlas,需确认堡垒机IP已加入Atlas的IP白名单
内容的提问来源于stack exchange,提问作者Baptiste Bortot
相关产品推荐
相关产品推荐

