使用uwsgi和Nginx部署Flask应用

部署方案

任何的部署方案都不应该脱离实际需求。Flask+uWSGI+Nginx 可以应对那些高并发、高性能的页面需求。
如果你需要:

  • 轻量、可扩展的Web程序
  • 易于使用的语法
  • 适于高连接并发的情况
  • 高性能、低占用
  • 多app管理
  • 高度可定制

这样的Web应用,那么Flask+uWSGI+Nginx 是你应该考虑的方案。

Flask

Flask是一个使用 Python 编写的轻量级 Web 应用框架。

uWSGI

The uWSGI project aims at developing a full stack for building hosting services.

Nginx

Nginx 是一个高性能的HTTP和 反向代理 服务器 (这里主要用于处理静态文件)。

部署环境

我们这里使用了Ubuntu 14.04 x64的VPS来部署我们的应用。

开始部署

配置virtualenv

生产环境中不同的Application往往依赖于不同的Python包。如果直接安装这些包,可能由于依赖的版本不同产生各种各样的冲突。为了避免这种情况,我们使用Virtualenv来为每个应用创建单独的虚拟环境,避免冲突。
Ubuntu的软件源中包含了virtualenv,可以直接安装:

1
# apt-get install python-virtualenv

如果使用Python3:

1
# apt-get install python3-virtualenv

或者使用pip安装:

1
$ pip install virtualenv

创建一个virtualenv环境是非常简单的。

1
$ virtualenv venv

Python环境和一些必要的工具(如pip)会被安装到当前目录的venv文件夹下。
当你想激活它时,执行

1
$ . venv/bin/activate

好了,你已经切换到了venv的shell下。值得注意的是,只有Python环境是虚拟的,其他环境(如C++ Lib)仍与之前没有任何区别。

上传应用

可以通过scp命令将本地的项目上传到远程主机中:

1
2
3
usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]        
[-l limit] [-o ssh_option] [-P port] [-S program]
[[user@]host1:]file1 ... [[user@]host2:]file2

也可以通过git等其它方式进行部署。

使用Manager启动Server

Manager是一个flask脚本,包含在flask.ext.script中。
新建manage.py,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Set the path
import os
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from flask.ext.script import Manager, Server, Shell
from yourpackagename import app

manager = Manager(app)


# Turn on debugger by default and reloader
manager.add_command("runserver", Server(
use_debugger=True,
use_reloader=True,
host='0.0.0.0')
)

manager.add_command("shell", Shell())

if __name__ == "__main__":
manager.run()

这样,我们就可以通过下面的命令,更方便地运行和调试项目:

1
2
$ python manage.py runserver    #服务器模式
$ python manage.py shell #Shell模式

安装所有需要的包

对Python而言,迁移我们的依赖是非常容易的。
pip freeze > requirements.txt将包依赖信息保存,而pip install -r requirements.txt会自动从网上下载并安装所有包。
在你Application的本地的virtualenv环境中生成requirements.txt,然后在remote的virtualenv环境中安装它们。

注意:保证对每个应用的环境是干净的。

配置uwsgi

先安装uwsgi:

1
$ pip install uwsgi

在应用目录中新建config.ini,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[uwsgi]

# uwsgi 启动时所使用的地址与端口
socket = 127.0.0.1:8001

# python 启动程序文件
wsgi-file = manage.py

# python 程序内用以启动的 application 变量名
callable = app

# 处理器数
processes = 4

# 线程数
threads = 2

# 状态检测地址
stats = 127.0.0.1:9191

# uwsgi 使用的协议
protocol=http

一些选项(如处理器数、线程数)不是必要的,更多选项可以参考uwsgi文档
测试一下是否成功:

1
$ uwsgi config.ini

配置supervisor

Supervisor是一个进程管理工具。这里使用它进行uwsgi进程的管理,以实现后台运行、自动重启。
在Ubuntu下可以直接通过下面的命令安装Supervisor:

1
# apt-get install supervisor

安装好后,只需要在/etc/supervisor/conf.d/ 新建一个配置文件,就可以增加一个Supervisor进程。
例如,我们的应用目录在主目录下,名为flask-app。新建一个flask-app.conf,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[program:flask-app]
# 启动命令入口
command= /home/your-username/flask-app/venv/bin/uwsgi /home/mocimy/flask-app/config.ini

# 命令程序所在目录
directory=/home/your-username/flask-app

# 运行命令的用户名
user=your-username

# 自动启动
autostart=true

# 自动重启
autorestart=true

#日志地址
stdout_logfile=/log/uwsgi_supervisor.log

快使用supervisor启动我们的应用看看吧!

1
2
# service supervisor restart
# supervisorctl #进程管理

supervisorctl可以管理/etc/supervisor/conf.d 下配置好的所有进程。
start 启动进程
stop 终止进程
status 查看进程状态

配置nginx

为什么还要使用nginx?可以看这里:https://serverfault.com/questions/590819/why-do-i-need-nginx-when-i-have-uwsgi
简单来说nginx更安全、帮助我们更好地处理静态资源。

1
# apt-get install nginx   #安装

推荐修改/ext/nginx/sites-available/default文件,不需要改动/etc/nginx/nginx.conf
修改server配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name localhost; #填写公网IP/域名

location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8001; //和uwsgi中的设置保存一致
uwsgi_param UWSGI_PYHOME /home/your-username/flask-app/venv; # 指向虚拟环境目录
uwsgi_param UWSGI_CHDIR /home/your-username/flask-app; # 指向网站根目录
uwsgi_param UWSGI_SCRIPT manage:app; # 指定启动程序
}
}

重启nginx:

1
# service nginx restart

大功告成,快打开浏览器查看一下吧!

总结

许多教程给出的解决方案由于版本不同、环境配置不同、搭建需求不同等等原因不能照搬到实际部署中。查阅官方文档、总结经验、反复调试是解决问题的最佳途径。Python的Server搭建相对PHP来说更困难,但也有着其独有的优势,值得尝试。