使用 Fabric 自动化部署

23027 67 2017年4月30日

使用 Nginx 和 Gunicorn 部署 Django 博客 中,我们通过手工方式将代码部署到了服务器。整个过程涉及到十几条命令,输了 N 个字符。一旦我们本地的代码有更新,整个过程又得重复来一遍,这将变得非常繁琐。

使用 Fabric 可以在服务器中自动执行命令。因为整个代码部署过程都是相同的,只要我们用 Fabric 写好部署脚本,以后就可以通过运行脚本自动完成部署了。

安装 Fabric

Fabric 目前仅支持 Python2,如果你的系统中只有 Python3 版本,请先安装一个 Python2 的版本,推荐安装 Python 2.7。Python3 和 Python2 可以共存于一个系统,所以不用担心同时安装两个版本的 Python 会发生冲突。

接下就可以简单地通过 pip 命令安装 Fabric 了。注意要使用 Python2 环境下的 pip,这样才能把 Fabric 安装到 Python2 环境下。

pip install fabric

部署过程回顾

在写 Fabric 脚本之前,我们先来回顾一下当我们在本地开发环境下更新了代码后,在服务器上的整个部署过程。

  1. 远程连接服务器。
  2. 进入项目根目录,从远程仓库拉取最新的代码。
  3. 如果项目引入了新的依赖,需要执行 pip install -r requirement.txt 安装最新依赖。
  4. 如果修改或新增了项目静态文件,需要执行 python manage.py collectstatic 收集静态文件。
  5. 如果数据库发生了变化,需要执行 python manage.py migrate 迁移数据库。
  6. 重启 Nginx 和 Gunicorn 使改动生效。

整个过程就是这样,把每一步操作翻译成 Fabric 对应的脚本代码,这样一个自动化部署脚本就完成了。

编写 Fabric 脚本

Fabric 脚本通常位于 fabfile.py 文件里,因此先在项目根目录下建一个 fabfile.py 文件。

根据上述过程编写的脚本代码如下:

blogproject/fabfile.py

from fabric.api import env, run
from fabric.operations import sudo

GIT_REPO = "you git repository"  

env.user = 'you host username' 
env.password = 'you host password'

# 填写你自己的主机对应的域名
env.hosts = ['demo.zmrenwu.com']

# 一般情况下为 22 端口,如果非 22 端口请查看你的主机服务提供商提供的信息
env.port = '22'


def deploy():
    source_folder = '/home/yangxg/sites/zmrenwu.com/django-blog-tutorial' 

    run('cd %s && git pull' % source_folder) 
    run("""
        cd {} &&
        ../env/bin/pip install -r requirements.txt &&
        ../env/bin/python3 manage.py collectstatic --noinput &&
        ../env/bin/python3 manage.py migrate
        """.format(source_folder))  
    sudo('restart gunicorn-demo.zmrenwu.com') 
    sudo('service nginx reload')

① 你的代码托管仓库地址。

② 配置一些服务器的地址信息和账户信息,各参数的含义分别为:

  • env.user:用于登录服务器的用户名
  • env.password:用户名对应的密码
  • env.hosts:服务器的 IP 地址,也可以是解析到这个 IP 的域名
  • env.port:SSH 远程服务器的端口号

③ 需要部署的项目根目录在服务器上的位置。

④ 通过 run 方法在服务器上执行命令,传入的参数为需要执行的命令,用字符串包裹。这里执行了两条命令,不同命令间用 && 符号连接:

  1. cd 命令进入到需要部署的项目根目录
  2. git pull 拉取远程仓库的最新代码

⑤ 对应上述部署过程中 3-5 的几条命令。因为启用了虚拟环境,所以运行的是虚拟环境 ../env/bin/ 下的 pip 和 python

⑥ 重启 Gunicorn 和 Nginx,由于这两条命令要在超级权限下运行,所以使用了 sudo 方法而不是 run 方法。

注意全部的脚本代码要放在 deploy 函数里,Fabric 会自动检测 fabfile.py 脚本中的 deploy 函数并运行。

由于脚本中有登录服务器的用户名和密码等敏感信息,不要把 fabfile.py 文件也上传到公开的代码托管仓库。

执行 Fabric 自动部署脚本

进入 fabfile.py 文件所在的目录,在 Python2 的环境下用 fab 命令运行这个脚本文件。

比如我的是 Windows 环境,Python2 安装在 C:\Python27\ 下,那么运行:

C:\Python27\Scripts\fab deploy

这时 Fabric 会自动检测到 fabfile.py 脚本中的 deploy 函数并运行,你会看到命令行输出了一系列字符串,如果在最后看到

Done. Disconnecting from zmrenwu.com... done.

说明脚本运行成功。

而如果看到

Aborting. Disconnecting from zmrenwu.com... done.

说明脚本运行中出错,检查一下命令行输入的错误信息,修复问题后重新运行脚本即可。以后当你在本地开发完相关功能后,只需要执行这一个脚本文件,就可以自动把最新代码部署到服务器了。

总结

本章节的代码位于:Step15: deploy automatically using fabric

如果遇到问题,请通过下面的方式寻求帮助。

  • 在下方评论区留言。
  • 将问题的详细描述通过邮件发送到 djangostudyteam@163.com,一般会在 24 小时内回复。
  • Pythonzhcn 社区的新手问答版块 发布帖子。

-- EOF --

最后更新:2018-11-11 12:21:12

67 条评论 / 38 人参与
硬核玩家陆一默

博主我在跑sudo python3 manage.py makemigrations

import markdownImportError: No module named 'markdown'

会找不到markdown模块

但是用pip安装又会提示Requirement already satisfied: markdown in /home/luzihai/sites/yimo.pro/env/lib/python3.5/site-packages (3.0.1)


追梦人物 [博主] 硬核玩家陆一默

你有激活虚拟环境吗?


Arrowarcher

采用pip3 install fabric3 

其他操作没什么变化:

参考

https://blog.csdn.net/qq_41854273/article/details/83344255


kevinjobs

回复上面那条,我自己搜索到怎么用密钥文件登陆了

把 env.password 替换为 env.key_filename 即可,如下所示

env.key_filename = '/path/to/key'

替换为你自己的 key 路径即可。

另外我按照博主教程写网站已经上线了 http://blog.mintin.me,自己重写了 CSS,大家互相参考下。

非常感谢博主的教程。


kevinjobs

AWS 的服务器用的是密钥文件登录,应该怎么搞哦


xusanpang

博主你好,执行fab deploy 出现这种问题是怎么回事呢?

out: django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the STATIC_ROOT setting to a filesystem path.


xusanpang xusanpang

知道错哪里了。。


lenkenlau

还有个细节:

还记得在 ubuntu16 下,自动启动 gunicorn 的脚本是不同于博主的,所以gunicorn的重启命令这里也要换掉:

# sudo('restart gunicorn-www.liuliqun.top')
sudo('systemctl restart lenkenlau.service')

萨摩耶好可爱 lenkenlau

你好,sudo('systemctl restart lenkenlau.service')这里的lenkenlau是什么呀


lenkenlau 萨摩耶好可爱

.service文件应该是你的配置信息,lenkenlau 只是我自定义的名字而已


lenkenlau

env.hosts 填域名会报错:查找该域名失败

换成IP地址就好了...不清楚为什么?


xuyy2

能不能写个shell 脚本实现上面的功能


xinyuebaiyun

自动部署拉取什么文件的代码?blog等应用里的?


玄虚

我用 supervisor 更方便。