部署前应用配置

开发环境与生产环境中的应用一般会有两套不同的配置。比如 DEBUG 选项,数据库配置等。

对于 setting.py 文件, 在生产环境中我们要设置 DEBUG, SECRET_KEY 以及数据库密码等私密的设置。为了项目的安全这些设置应该最好从环境变量加载,或从仅供服务的文件中读取。

为了更好的统一线上和线下两个环境, 我们使用 python-dotenv 工具. 有了这个工具, 我们可以将配置信息写在 .env 文件中,然后使用下面的代码加载配置信息到环境变量中:

# settings.py
from dotenv import load_dotenv
load_dotenv()

具体配置方法:

  1. 进入虚拟环境, 安装 python-dotenv
pip install python-dotenv
  1. 在 Django 项目根目录处建立 .env 文件(与manage.py 同目录), 并添加配置
DJANGO_DEBUG=Ture
  1. 修改 setting.py 文件,将一些关键配置改成从环境变量中读取, 没有就设为默认值
import os
from dotenv import load_dotenv
load_dotenv()
SECRET_KEY = os.environ.get('SECRET_KEY', 'mzi&f@)*4985)m19oj+x-hg4$hi!478v)+dz)bh+mgiz!zjg9n')
DEBUG = os.environ.get('DJANGO_DEBUG', False)
# 当 DEBUG=Flase 时, 设置的能够访问的主机
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '.xxmblog.top', '<服务器的IP地址>']
# 数据库设置, 便于在生产环境中直接改为 MySQL 数据库
DATABASES = {
    'default': {
        'ENGINE': os.environ.get('DATABASE_ENGINE') or 'django.db.backends.sqlite3',
        'NAME': os.environ.get('DATABASE_NAME') or os.path.join(BASE_DIR, 'db.sqlite3'),
        'USER': os.environ.get('DATABASE_USER'),     # 用户名,可以自己创建用户
        'PASSWORD': os.environ.get('DATABASE_PASSWORD'),  # 密码
        'HOST': os.environ.get('DATABASE_HOST'),  # mysql服务所在的主机ip
        'PORT': os.environ.get('DATABASE_PORT'),         # mysql服务端口
# ...
STATIC_URL = '/static/'
# 增加下面的, 便于在生产环境中收集静态文件
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

接下来,关键的是,.env 保存一些私密的配置,不要添加到git中。

开发环境的 .env:

DJANGO_DEBUG 为非空字符串时为 Ture, 不设置默认为 Flase
# 其他一些数据库配置

生产环境中的 .env 设置后面单独说明。

当有其他生产环境和开发环境不同的配置时,都让Django从环境变量中读取,我们就写在.env 文件中。这样部署的时候就不用修改源代码了。

其他配置:

  • 静态文件收集
    为了使 Nginx 方便的处理静态文件的请求,生产环境中需要将全部静态文件收集到一个统一的目录下。
    先添加如下配置:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

STATIC_ROOT 指明了静态文件的收集目录,到生产环境中有用

  • 导出依赖库
    进入虚拟环境, 执行下列命令
pip freeze > requirements.txt

会生成一个 requirements.txt 文件, 里面包含了虚拟环境中安装的所有依赖。
到了服务器上,只需要执行

pip install -r requirements.txt

就能安装里面列的所有库了。

上传到 Github

注意到
.env文件不能上传,服务器应该自己建一个
db.sqlite3 不上传, 因为这是本地的测试数据库, 到了生产环境, 应该用其他的数据库了
venv 文件夹不上传

在服务器上安装应用

在自己的家目录下(如 home/xxm/) 创建文件夹

➜  ~ mkdir sites
➜  ~ mkdir sites/www.xxmblog.com

所有的网站放在 sites 目录中,网站的项目以域名区分, 进入 www.xxmblog.com 目录。
通过 git clone 将应用下载到该目录中
然后进入项目目录并创建虚拟环境:

$ python3 -m venv venv
$ source venv/bin/activate

此时的项目结构:

home/xxm/sites/www.xxmblog.top/blog-django/
                                    blogproject/
                                    venv/
                                    .gitignore
                                    requirements.txt

安装项目依赖

先安装必要的包

(venv) $ pip install -r requirements.txt

除了requirements.txt中的包之外,还要安装生产部署需要的两个包。gunicorn软件包是Python应用程序的生产Web服务器。 mysqlclient 软件包包含MySQL驱动程序

(venv) $ pip install gunicorn mysqlclient

如果安装 mysqlclient 出现错误, 运行下面的命令。

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install pymysql
pip install mysqlclient

配置 MySQL

MySQL 的安装不做说明, 具体讲述如何让 Django 使用 MySQL 数据库。

下列命令创建名为 blog-django 的新数据库,并创建一个具有完全访问权限的同名用户:

mysql> create database blogdjango character set utf8 collate utf8_bin;
mysql> create user 'blogdjango'@'localhost' identified by '<db-password>';
mysql> grant all privileges on blogdjango.* to 'blogdjango'@'localhost';
mysql> flush privileges;
mysql> quit;

需要用你选择的密码来替换<db-password>, 这将是 blogdjango 数据库用户的密码,所以不要使用你已为root用户选择的密码

接下来就是修改 setting.py 文件,让 Django 使用刚刚创建的数据库。但是由于我们前面使用了 dotenv,seeting.py 的一些配置已经从环境变量中读取, 所以我们只需配置 .env 文件即可

配置 .env

创建一个 .env 文件, 与 manage.py 同目录。

在里面输入:

SECRET_KEY=<随机字符串>
DATABASE_ENGINE=django.db.backends.mysql
DATABASE_NAME=blogdjango
DATABASE_USER=blogdjango
DATABASE_PASSWORD=<刚刚创建用的密码>
DATABASE_HOST=localhost
DATABASE_PORT=3306

SECRET_KEY 使用一个随机字符串
DJANGO_DEBUG 不设置时,DEBUG为FALSE
其他为MySQL的数据库配置

收集静态文件

虚拟环境下继续运行 python manage.py collectstatic 命令收集静态文件到 static 目录下:

数据库迁移

虚拟环境下继续运行 python manage.py migrate 命令创建数据库文件:

python manage.py makemigrations
python manage.py migrate

创建超级用户

虚拟环境下继续运行 python manage.py createsuperuser 命令创建一个超级用户,方便我们进入 Django 管理后台

尝试运行一下应用

python manage.py runserver

如果上面的命令没有出错的话,一般就没有问题了。

设置 Gunicorn 和 Supervisor

当使用 python manage.py runserver 运行服务器时, 我们使用的是 Django 自带的Web服务器。这个服务器在开发过程中很有用,但并不适用于生产环境,所以我们改用 Gunicorn, 它是一个纯粹的Python Web服务器, 并且支持高并发。

尝试在 gunicorn 下启动 blogproject:

gunicorn -b localhost:8000 -w 4 blogproject.wsgi:application

-b 告诉 gunicorn 在哪里监听请求,我在8000端口上监听了内部网络接口。在没有外部访问的情况下,运行 Python Web 服务器很快。当有外部请求的时候,我们就需要一个更快的Web服务器,比如 nginx,它可以优化客户端的所有静态文件的请求,并将任何请求转发到内部服务器。后面我们会设置 nginx。
-w 配置gunicorn将运行多少worker
blogproject.wsgi:application 告诉gunicorn如何加载应用程序实例. 冒号前的名称是包含应用程序的模块,冒号后面的名称是此应用程序的名称。

运行了上面的命令后,我们看到:

(venv) ➜  blogproject git:(master) ✗ gunicorn -b localhost:8000 -w 4 blogproject.wsgi:application
[2019-08-16 11:18:50 +0800] [5674] [INFO] Starting gunicorn 19.9.0
[2019-08-16 11:18:50 +0800] [5674] [INFO] Listening at: http://127.0.0.1:8000 (5674)
[2019-08-16 11:18:50 +0800] [5674] [INFO] Using worker: sync
[2019-08-16 11:18:50 +0800] [5677] [INFO] Booting worker with pid: 5677
[2019-08-16 11:18:50 +0800] [5678] [INFO] Booting worker with pid: 5678
[2019-08-16 11:18:50 +0800] [5680] [INFO] Booting worker with pid: 5680
[2019-08-16 11:18:50 +0800] [5679] [INFO] Booting worker with pid: 5679

gunicorn 监听 http://127.0.0.1:8000, 并启动了4个worker.
[Ctrl+C] 退出进程。

可以看到,目前我们想要启动服务器,每次都要输入一遍上面的命令,如果进程崩溃了,还要手动输入上面的命令让服务器重新启动。这真的很傻,所以我们使用一个 supervisor 的应用。

supervisor 的功能:

  • 可以让这个进程后台运行,并持续监控
  • 如果服务器崩溃退出,这个进程可以重新自动启动
  • 而且如果机器重新启动,服务器在启动时自动运行,而无需人工登录和启动
sudo apt-get install supervisor

supervisor 使用配置文件来告诉它要监视什么程序以及如何在必要时重新启动它们

配置文件必须存储在 /etc/supervisor/conf.d

对于我们这个 blogproject 应用,我们创建一个 blogproject.conf 配置文件:
/etc/supervisor/conf.d/blogproject.conf:Supervisor配置。

[program:blogproject]
command=/home/xxm/sites/www.xxmblog.com/blog-django/venv/bin/gunicorn -b localhost:8000 -w 4 blogproject.wsgi:application
directory=/home/xxm/sites/www.xxmblog.com/blog-django/blogproject
user=xxm
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true

commanddirectoryuser设置告诉supervisor如何运行应用程序。 如果计算机启动或崩溃,autostartautorestart设置会使microblog自动重新启动。 stopasgroupkillasgroup选项确保当supervisor需要停止应用程序来重新启动它时,它仍然会调度成顶级gunicorn进程的子进程。

编写此配置文件后,必须重载supervisor服务的配置才能导入它:

$ sudo supervisorctl reload

像这样,这个gunicorn web服务器就已经启动和运行,并处于监控之中!

查看状态:

sudo supervisorctl status

如果出现下面的内容,可能是配置文件出错了

blogproject                      FATAL     Exited too quickly (process log may have details)

如果是下面表示正在运行:

blogproject                      RUNNING   pid 5865, uptime 0:00:03
sudo supervisorctl stop xxx # 关闭 xxx
sudo supervisorctl restart xxx # 重启 xxx

配置 Nginx

由 gunicorn 启动的 blogproject 应用服务器现在运行在本地端口8000. 我们想要让服务器能够被外部世界访问。

首先打开两个端口 80 和 443 用来处理应用程序的 Web 通讯。如果是阿里云服务器需要在控制台上配置安全组。

我们直接使用 https, 配置端口80将所有流量转发到将要加密的端口443.

首先创建一个 SSL 证书, 这个证书只能用来测试,当用户访问的时候, Web 浏览器会警告用户证书不是由可信证书颁发机构颁发的。

mkdir certs
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
  -keyout certs/key.pem -out certs/cert.pem

生成的时候填写的信息,将包含在 SSL 证书中, 用户在浏览器访问的时候可以查看。

命令的结果将生成名为key.pem和cert.pem的两个文件。

为了使用 nginx, 为我们就要编写一个配置文件,这个文件位于 /etc/nginx/sites-enabled 中,
通常刚安装完 Ngnix,在这个位置有一个默认的测试站点, 我们将其删除:

$ sudo rm /etc/nginx/sites-enabled/default

然后创建 blogproject 配置文件:
/etc/nginx/sites-enabled/blogproject:Nginx配置。

server {
    # 监听 80 端口
    listen 80;
    server_name _;
    location / {
        # redirect any requests to the same URL but on https
        return 301 https://$host$request_uri;
server {
    # 监听 443 端口
    listen 443 ssl;
    # 服务器域名
    server_name _;
    # 刚刚生成的自签名ssl证书的位置
    ssl_certificate /home/xxm/sites/www.xxmblog.com/blog-django/certs/cert.pem;
    ssl_certificate_key /home/xxm/sites/www.xxmblog.com/blog-django/certs/key.pem;
    # 将访问和错误日志写入 /var/log
    access_log /var/log/microblog_access.log;
    error_log /var/log/microblog_error.log;
    location / {
        # forward application requests to the gunicorn server
        proxy_pass http://localhost:8000;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # 所有URL 带有 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录。
    location /static {
        alias /home/xxm/sites/www.xxmblog.com/blog-django/blogproject/static;
        expires 30d;

添加此文件后,你需要告诉nginx重新加载配置以激活它:

$ sudo service nginx reload

浏览器输入域名或者服务器的IP地址,应该可以看到访问成功了。

当应用更新的时候,往往需要重复下列的过程:

  1. 从 github 中拉取应用
git pull
  1. 可能需要修改 .env 文件, 增加环境变量
  2. 进入虚拟环境, 安装额外的依赖
pip install -r requirements.txt
  1. 收集静态文件
python manage.py collectstatic
  1. 数据库迁移
python manage.py makemigrations
python manage.py migrate
sudo supervisorctl restart blogproject
  1. 重启nginx
sudo service nginx reload
                                    文章目录前言1.	在云服务器上安装mysql数据库2. 准备云上的flask环境3. 将项目部署gunicorn 上4.	部署Nginx参考资料
本文是一篇flask项目部署的入门教程,记录了在阿里云上从数据库的安装到最终项目的部署的全过程以及过程中遇到的一些问题。参考的资料在本文的最下面,在过程中有使用到也会把链接附在旁边。内容相对独立可以跳看需要的部分。
1.	在云服务器上安装mysql数据库
在云服务器上mysql的使用和本地的区别只在于要提供外部访问的账号和接口
安装的方法一般有两种一种
                                    (小编的环境为python3.6,django==2.1.2)
Gunicorn是一个unix上被广泛使用的高性能的Python WSGI UNIX HTTP Server(即一种服务器)。和大多数的web框架兼容,并具有实现简单,轻量级,高性能等特点。
Nginx是一个高性能的静态服务器,支持负载均衡,多进程,多线程,数据压缩,日志监控,限流等多种功能。是目前比较主流的服务器
Nginx是一个http服务器,可以做请求转发,负载均衡   (处理静态资源,并将动态请求转发给GunicornGunicorn是一个实现了wsgi的一个处理python代码的服务器  (处理动态请求)
分析图如下:
                                    文章目录第一步建立虚拟环境:使用 manage.py runserver ip:port运行使用gunicorn运行supervisor运行gunicorn.指定路径生成supervisor配置文件:修改supervisor配置文件使用指定路径的supervisor配置文件运行起来后nginx查找一下nginx的路径配置nginx配置文件重启nginx服务配置nginx遇到的bug./nginx ...
                                    djangonginxsupervisorgunicorn,gevent这几个都是在本领域大名鼎鼎的软件,下面的部署都是在ubuntu12.04里面验证成功的!
首先是安装这些软件在ubuntu下面都比较简单,nginx和supservisor的安装如下
apt-get install nginx,supervisor在ubuntu下使用python,强烈建议安装python-dev