fabric 2+需为每台服务器显式创建connection实例,并用threadpoolexecutor并发执行;主机格式为"user@host",密码登录传connect_kwargs={"password": "xxx"},密钥登录推荐connect_kwargs={"key_filename": "/path/id_rsa"},命令用conn.run("cmd", hide=true)并检查result.stdout.strip(),sudo需pty=true,超时长任务加timeout参数。

直接用 fabric 3.x 版本(即 fabric3 已淘汰,官方维护的是 fab 命令 + invoke 底层)能跑通多机命令,但必须注意连接模型已从 Fabric 1.x 的「主机列表直连」变成「Connection 实例驱动」——不改写法会卡在连接失败或只执行第一台。
怎么写一个能同时 ssh 到多台服务器的 task?
Fabric 2+ 不再支持 env.hosts 全局配置,每台机器都要显式构造 Connection。常见错误是把主机列表传给单个 Connection,结果只连上第一个。
- 用
ThreadPoolExecutor并发创建多个Connection实例,每个实例对应一台服务器 -
Connection初始化时必须带host(如"user@192.168.1.10"),不能只传 IP - 密码登录需传
connect_kwargs={"password": "xxx"};密钥更推荐,用connect_kwargs={"key_filename": "/path/id_rsa"} - 命令执行统一用
conn.run("ls -l", hide=True),hide=True可避免输出混杂,需要结果再取result.stdout
为什么 run() 返回的 result.stdout 有时为空?
不是命令没执行,而是默认情况下 Fabric 不捕获 stdout/stderr,除非你显式设置 hide=False 或指定 pty=True(后者用于需要交互的命令,比如 sudo 提示输入密码)。
- 简单命令(
ls,uptime)用conn.run("cmd", hide=True)后检查result.stdout.strip() - 涉及
sudo且没配 NOPASSWD 的场景,必须加pty=True,否则卡住无响应 - 如果命令本身输出到 stderr(比如编译警告),要读
result.stderr,stdout为空是正常的 - 超时默认 10 秒,长任务记得加
timeout=60参数
如何避免密钥权限被拒绝(Permission denied (publickey))?
不是密钥文件路径错,就是 sshd 配置或 key 权限太宽松。Fabric 本身不校验私钥权限,但 OpenSSH 会拒绝读取权限大于 600 的私钥文件。
- 确认私钥文件权限:运行
chmod 600 ~/.ssh/id_rsa,否则 Fabric 会静默失败 - 用
ssh -i /path/key user@host手动测试通不通,不通就别指望 Fabric 能过 - 如果目标服务器禁用了密码登录,又没正确部署公钥,
Connection会直接抛AuthenticationException - 企业环境常用跳板机,得用
gateway=Connection("jump-host")参数链式连接,不能靠 SSH Config 自动跳转
真正麻烦的从来不是写几行并发代码,而是每台服务器的 SSH 状态、sudo 权限、Python 环境版本、甚至 shell 类型(有些老系统默认是 dash 不是 bash)都会让同一段 run() 行为不一致。建议先用 conn.run("echo $SHELL; python3 --version") 探活再批量操作。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











