作者:HelloGitHub-追梦人物
文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库
在上一篇教程中,我们通过手工方式将代码部署到了服务器。整个过程涉及到十几条命令,输了 N 个字符。一旦我们本地的代码有更新,整个过程又得重复来一遍,这将变得非常繁琐。
使用 Fabric 可以在服务器中自动执行命令。因为整个代码部署过程都是相同的,只要我们用 Fabric 写好部署脚本,以后就可以通过运行脚本自动完成部署了。
首先在本地安装 Fabric:
$ pipenv install fabric --dev因为 Fabric 只需在本地使用,因此使用 --dev 选项,让 Pipenv 将 Fabric 依赖写到 dev-packages 配置下,线上环境就不会安装 Fabric。
部署过程回顾在写 Fabric 脚本之前,先来回顾一下当我们在本地开发环境下更新了代码后,在服务器上的整个部署过程。
远程连接服务器。
进入项目根目录,从远程仓库拉取最新的代码。
如果项目引入了新的依赖,需要执行 pipenv install --deploy --ignore-pipfile 安装最新依赖。
如果修改或新增了项目静态文件,需要执行 pipenv run python manage.py collectstatic 收集静态文件。
如果数据库发生了变化,需要执行 pipenv run python manage.py migrate 迁移数据库。
重启 Nginx 和 Gunicorn 使改动生效。
整个过程就是这样,把每一步操作翻译成 Fabric 对应的脚本代码,这样一个自动化部署脚本就完成了。
完善项目配置 分离 settings 文件为了安全,线上环境我们将 debug 改为了 False,但开发环境要改为 True,改来改去将很麻烦。此外,django 的 SECRET_KEY 是很私密的配置,django 的很多安全机制都依赖它,如果不慎泄露,网站将面临巨大安全风险,像我们现在这样直接写在配置文件中,万一不小心公开了源代码,SECRET_KEY 就会直接泄露,好的实践是将这个值写入环境变量,通过从环境变量取这个值。
解决以上问题的一个方案就是拆分 settings.py 文件,不同环境对应不同的 settings 文件,django 在启动时会从环境变量中读取 DJANGO_SETTINGS_MODULE 的值,以这个值指定的文件作为应用的最终配置。
我们来把 settings.py 拆分,首先在 blogproject 目录下新建一个 Python 包,名为 settings,然后创建一个 common.py,用于存放通用配置,local.py 存放开发环境的配置,production.py 存放线上环境的配置:
blogproject\ settings\ __init__.py local.py production.py settings.py将 settings.py 文件中的内容全部复制到 common.py 里,并将 SECRET_KEY、DEBUG、ALLOWED_HOSTS 这些配置移到 local.py 和 production.py 中(common.py 中这些项可以删除)。
开发环境的配置 local.py 内容如下:
from .common import * SECRET_KEY = 'development-secret-key' DEBUG = True ALLOWED_HOSTS = ['*']线上环境的配置:
from .common import * SECRET_KEY = os.environ['DJANGO_SECRET_KEY'] DEBUG = False ALLOWED_HOSTS = ['hellodjango-blog-tutorial.zmrenwu.com']注意这里我们在顶部使用 from .common import * 将全部配置从 common.py 导入,然后根据环境的不同,在下面进行配置覆盖。
线上环境和开发环境不同的是,为了安全,DEBUG 模式被关闭,SECRET_KEY 从环境变量获取,ALLOWED_HOSTS 设置了允许的 HTTP HOSTS(具体作用见后面的讲解)。
以上操作完成后,一定记得删除 settings.py。
现在我们有了两套配置,一套是 local.py,一套是 production.py,那么启动项目时,django 怎么知道我们使用了哪套配置呢?答案是在运行 manage.py 脚本时,django 默认帮我们指定了。在使用 python manage.py 执行命令时,django 可以接收一个 --settings-module 的参数,用于指定执行命令时,项目使用的配置文件,如果参数未显示指定,django 会从环境变量 DJANGO_SETTINGS_MODULE 里获取。看到 manage.py 的源码:
def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blogproject.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv)可以看到这个 main 函数,第一行的 setdefault 为我们设置了环境变量 DJANGO_SETTINGS_MODULE 的值,这句代码的作用是,如果当前环境中 DJANGO_SETTINGS_MODULE 的值没有被设置,就将其设置为 blogproject.settings,所以我们使用 python manage.py 执行命令时,django 默认为我们使用了 settings.py 这个配置。
所以我们可以通过设置环境变量,来指定 django 使用的配置文件。