Fabric3是当前Django多机部署的可行选择,因其将已停止维护的Fabric 1.14.0成功移植至Python 3.7+,保留env.hosts、run()、sudo()等直觉式API,兼容旧有Django部署脚本,避免Fabric 2.x的Connection对象不兼容问题。

为什么 fabric3 是当前 Django 多机部署的可行选择
Fabric 2.x 彻底重写了 API,和老项目里常见的 fab 命令、env.hosts、@task 装饰器不兼容;而原始 Fabric 1.x 已停止维护,PyPI 上的 fabric 包(v2+)默认走 invoke + fabric2 模式,无法直接跑旧式 Django 部署脚本。实际能用、有维护、支持 Python 3.7+ 且保留类 Fabric 1 风格的,只有社区延续分支 fabric3——它只是把 Fabric 1.14.0 移植到 Python 3,并修复了部分 SSH 连接和 sudo 行为问题。
如果你的部署逻辑依赖 env.hosts、run()、sudo()、put() 这套直觉式写法,别强上 fabric2,直接装:
pip install fabric3
否则后续所有任务都会报 AttributeError: 'Connection' object has no attribute 'run' 或 No module named 'fabric.api'。
如何组织 fabfile.py 支持多环境(staging / production)和多角色(web / db)
Django 部署常需区分服务器角色(比如 web 节点跑 Gunicorn,db 节点只配 PostgreSQL),同时避免 staging 和 production 共用同一组 host 导致误操作。Fabric 1 / fabric3 的 env 全局对象仍是最轻量的配置载体,但必须配合 @hosts 或 @roles 显式约束执行范围。
推荐结构如下:
from fabric.api import env, task, roles, runs_once
from fabric.contrib.project import rsync_project
<h1>全局基础配置(不随环境变)</h1><p>env.user = 'deploy'
env.use_ssh_config = True # 读 ~/.ssh/config,方便管理别名和密钥路径</p><h1>环境分组(按需调用 fab staging deploy 或 fab production deploy)</h1><p>@task
def staging():
env.roledefs = {
'web': ['web-stg.example.com'],
'db': ['db-stg.example.com'],
}
env.project_root = '/var/www/myproject-stg'
env.git_branch = 'develop'</p><p>@task<br>
def production():
env.roledefs = {
'web': ['web1.prod.example.com', 'web2.prod.example.com'],
'db': ['db-main.prod.example.com'],
}
env.project_root = '/var/www/myproject-prod'
env.git_branch = 'main'</p><h1>部署主任务,用 @roles 限定只在 web 节点执行</h1><p>@task
@roles('web')
def deploy():
run(f'cd {env.project_root} && git pull origin {env.git_branch}')
run(f'cd {env.project_root} && pip install -r requirements.txt')
run(f'cd {env.project_root} && python manage.py migrate --noinput')
run(f'cd {env.project_root} && python manage.py collectstatic --noinput')
sudo('systemctl restart gunicorn@myproject')</p>
注意:这里没写 db 相关操作(如 dump/restore),因为 @roles('web') 会自动跳过 db 主机;若需在 db 节点运行命令,单独写个 @roles('db') 任务即可。
常见失败点:sudo 权限、虚拟环境路径、Python 解释器错位
Fabric 默认用系统 Python 执行命令,但 Django 项目几乎都跑在 virtualenv 里。直接 run('python manage.py migrate') 很可能报 ModuleNotFoundError: No module named 'django'——因为 python 指向的是 /usr/bin/python,而非你 virtualenv 里的 venv/bin/python。
必须显式指定解释器路径或激活环境:
- 用完整路径最稳:
run('/var/www/myproject-prod/venv/bin/python manage.py migrate') - 或先 source(注意 shell 类型):
run('source /var/www/myproject-prod/venv/bin/activate && python manage.py migrate'),但某些 shell(如 dash)不支持source,得改用. -
sudo()默认不继承用户环境变量,若venv/bin/activate依赖$PATH,得加shell=False或手动设path参数 - 数据库迁移若涉及
sudo -u postgres,要确认目标用户有权限访问项目目录,否则Permission denied会静默失败
rsync_project 替代 scp,但要注意 exclude 规则写法
rsync_project 比手写 put() 更适合整站同步(尤其是 static/media),但它底层调用 rsync,exclude 规则必须符合 rsync 语法,不是 glob 也不是正则。
例如想排除本地 venv/、logs/ 和 .git/,但保留远程已有的 media/(通常挂载为独立卷):
rsync_project(
remote_dir=env.project_root,
local_dir='./',
exclude=('venv', 'logs', '.git', 'fabfile.py'),
delete=True,
)
注意:exclude 是元组,每项是字符串,不能写成 'venv/'(末尾斜杠会被忽略),也不能用 **/venv;delete=True 会删掉远程没有但本地有的文件,上线前务必确认。
fabric3 的多机部署链条很短,真正卡住人的从来不是“怎么写”,而是“哪台机器上哪个环境变量没生效”“sudo 切用户后 PATH 断了”“rsync 把 .env 文件同步过去覆盖了生产密钥”。把这些路径、权限、作用域写死在 fabfile.py 里,比追求抽象更可靠。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











