flask几种部署方式实践[转]

Flask生产部署

flask作为一款轻量级web框架,具有诸多优点。我喜欢它的原因是它具有高度的可扩展性,广泛的各类插件,丰富的开发文档。在开发调试过程中,我们往往会简单的使用flask自带的web服务器。但是在实际的生产环境中,flask自带的web服务器很难满足需求。
所以,在生产环境中,部署flask应该用什么呢?这首先就不得不说WSGI了。

WSGI

WSGI(python web server gateway interface),python web服务器网关接口。它是python语言定义的web服务器和web应用程序之间的一种简单通用的接口。WSGI可以分为两个部分:一个是服务器或者说是网关,另一个可以成为web应用或者说是应用框架。在处理来自前端的请求是,服务器会为应用程序提供环境上下文及一个回调函数。在应用程序完成请求之后,将先前的回调函数结果返回给前端。因此,对于flask而言,这里的WSGI可以起到的功能:

  1. 重写环境变量,根据目标url将请求消息路由到对应的应用对象;
  2. 允许在一个进程中运行多个web应用程序或者框架;
  3. 可以起到负载均衡远端请求的作用;
  4. 对请求或者返回内容进行处理。

因此,只要遵照WSGI协议的web应用都可以部署在对应的webserver之后。或者说WSGI之于python,就如同Fastcgi之于php。

独立的WSGI容器

如果同时有好几个东西在面前,能够实现的功能类似,我肯定会选择更容易操作的。在flask部署这件事情上,我会选择一些独立的WSGI容器来部署flask。

gunicorn

gunicorn是一个unix用的WSGI HTTP服务器。它是从ruby的unicorn项目中移植过来的。它基于”pre-fork worker”模型,会预先开启大量进程,等待并处理接收到的请求,每个单独进程可以同时处理它们各自接到的请求,避免进程启动和销毁的开销。但是gunicorn是基于阻塞式的io,并发能力稍弱。如果要想用它来部署flask应用相当简便。

  • 第一步,要通过pip安装gunicorn,pip install gunicorn
  • 在安装完成之后,通过命令:gunicorn -w 4 -b 127.0.0.1:4000 run:app就可以将所要启动的flask应用程序启动。
Python
→ gunicorn -w 4 -b 127.0.0.1:4000 run:app [2016-12-12 21:44:16 +0800] [81837] [INFO] Starting gunicorn 19.6.0 [2016-12-12 21:44:16 +0800] [81837] [INFO] Listening at: http://127.0.0.1:4000 (81837) [2016-12-12 21:44:16 +0800] [81837] [INFO] Using worker: sync [2016-12-12 21:44:16 +0800] [81840] [INFO] Booting worker with pid: 81840 [2016-12-12 21:44:16 +0800] [81841] [INFO] Booting worker with pid: 81841 [2016-12-12 21:44:16 +0800] [81842] [INFO] Booting worker with pid: 81842 [2016-12-12 21:44:16 +0800] [81843] [INFO] Booting worker with pid: 81843
1
2
3
4
5
6
7
8
9
→ gunicorn - w 4 - b 127.0.0.1 : 4000 run : app
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81837 ] [ INFO ] Starting gunicorn 19.6.0
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81837 ] [ INFO ] Listening at : http : / / 127.0.0.1 : 4000 ( 81837 )
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81837 ] [ INFO ] Using worker : sync
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81840 ] [ INFO ] Booting worker with pid : 81840
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81841 ] [ INFO ] Booting worker with pid : 81841
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81842 ] [ INFO ] Booting worker with pid : 81842
[ 2016 - 12 - 12 21 : 44 : 16 + 0800 ] [ 81843 ] [ INFO ] Booting worker with pid : 81843
 

其中-w指的是预定义的工作进程数,-b指的是要绑定的ip和端口,run是flask的启动python文件,app则是flask应用程序实例。比如说,我的run.py文件中是这样的

Python
app = Flask(__name__) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=4000)
1
2
3
4
app = Flask ( __name__ )
if __name__ == '__main__' :
     app . run ( debug = True , host = '0.0.0.0' , port = 4000 )
 

Tornado

Tornado,它是一款开源的可伸缩、非阻塞式的web服务器和工具集。在高并发的应用场景中有不错的效果。同样,要想通过Tornado来部署flask也是很简便的:

  • 第一步,通过pip安装pip install tornado
  • 第二部,在你的flask启动文件夹中新建py文件,然后输入这些内容,在启动的时候通过这个新建的文件启动即可
Python
from tornado.wsgi import WSGIContainer from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop from run import app http_server = HTTPServer(WSGIContainer(app)) http_server.listen(4000) IOLoop.instance().start()
1
2
3
4
5
6
7
8
from tornado . wsgi import WSGIContainer
from tornado . httpserver import HTTPServer
from tornado . ioloop import IOLoop
from run import app
http_server = HTTPServer ( WSGIContainer ( app ) )
http_server . listen ( 4000 )
IOLoop . instance ( ) . start ( )
 

Gevent

Gevent是一个基于协同程序的python库,与tornado的部署方式类似,通过gevent部署flask也是十分的便利:

from gevent.wsgi import WSGIServer
from run import app
http_server = WSGIServer(('', 4000), app)
http_server.serve_forever()

nginx http代理

单纯依靠上述的这些wsgi容器在生产环境中还是不够的,往往还要在这些容器前边在部署一个nginx做http转发。nginx可以起到负载均衡、流量控制、日志管理等等更加精细的工作。对nginx的配置文件做简单的修改即可完成

Python
server { listen 80; server_name _; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { proxy_pass http://127.0.0.1:4000/; 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; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
     listen 80 ;
 
     server _name _ ;
 
     access_log    / var / log / nginx / access . log ;
     error_log    / var / log / nginx / error . log ;
 
     location / {
         proxy_pass         http : / / 127.0.0.1 : 4000 / ;
         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 ;
     }
}
 

其他的部署方式

当然,除了通过上述几个wsgi容器来简单的部署flask以外,还有其他几种方式也可以选择:mod_wsgiuwsgifastcgicgi

进程管理工具supervisor

最近在找flask生产环境部署相关的内容,无意间碰到一个神器:supervisord
它是一个使用python编写的进程管理工具,可以很方便的开启、关闭或者重启进程。当你的主机不小心挂掉的时候,通过配制好的supervisord可以很方便的重启服务而不用一行一行敲命令。要想使用supervisord,只需要这几步:

  • 第一步,当然还是安装:sudo pip install supervisor
  • 安装完成之后,主要的任务就是要完成配置文件:echo_supervisord_conf > /path/to/supervisord.conf,先将supervisord的相关配置导出到指定路径以供修改;
  • 下面主要修改我们比较关注的部分:
Python
<br />[program:usercenter] directory = /home/leon/projects/usercenter ; 程序的启动目录 command = gunicorn -c gunicorn.py wsgi:app ; 启动命令,可以看出与手动在命令行启动的命令是一样的 autostart = true ; 在 supervisord 启动的时候也自动启动 startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了 autorestart = true ; 程序异常退出后自动重启 startretries = 3 ; 启动失败自动重试次数,默认是 3 user = leon ; 用哪个用户启动 redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB stdout_logfile_backups = 20 ; stdout 日志文件备份数 ; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件) stdout_logfile = /data/logs/usercenter_stdout.log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
< br / > [ program : usercenter ]
directory = / home / leon / projects / usercenter ; 程序的启动目录
command = gunicorn - c gunicorn . py wsgi : app    ; 启动命令,可以看出与手动在命令行启动的命令是一样的
autostart = true      ; 在 supervisord 启动的时候也自动启动
startsecs = 5          ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true    ; 程序异常退出后自动重启
startretries = 3      ; 启动失败自动重试次数,默认是 3
user = leon            ; 用哪个用户启动
redirect_stderr = true    ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB    ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20      ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录( supervisord 会自动创建日志文件)
stdout_logfile = / data / logs / usercenter_stdout . log
 

按照上边的内容,完成修改之后,比如说我的这个:

Python
[program:flask] command=python ./app/main/run.py [program:getmsg] command=python ./app/dataCollector/Collector/rocket.py
1
2
3
4
5
[ program : flask ]
command = python . / app / main / run . py
[ program : getmsg ]
command = python . / app / dataCollector / Collector / rocket . py
 

进入对应的目录,键入supervisord -c manage.conf就可以了

  • 接下来通过supervisorctl就可以查看当前进程运行的状态,启动或者关闭指定进程了:
Python
→ supervisorctl -c manage.conf flask RUNNING pid 79541, uptime 4:43:15 getmsg STOPPED Dec 12 07:17 PM supervisor> stop flask flask: stopped supervisor> status flask STOPPED Dec 12 09:43 PM getmsg STOPPED Dec 12 07:17 PM
1
2
3
4
5
6
7
8
9
10
→ supervisorctl - c    manage . conf
flask                             RUNNING   pid 79541 , uptime 4 : 43 : 15
getmsg                           STOPPED   Dec 12 07 : 17 PM
supervisor > stop flask
flask : stopped
supervisor > status
flask                             STOPPED   Dec 12 09 : 43 PM
getmsg                           STOPPED   Dec 12 07 : 17 PM
 
 

crontab在python虚拟环境中的使用

使用python开发的同学往往会使用virtualenv来使自己的开发环境纯净不受干扰,我在使用过程中需要将一个python脚本通过crontab定期执行。在编写了对应的crontab配置文件之后,并没有按照预想的方式来。

Python
0,15,30,45 * * * * python /home/eclipse/git/env/DouyuFan/app/dataCollector/Collector/allRooms.py
1
2
0 , 15 , 30 , 45 * * * * python / home / eclipse / git / env / DouyuFan / app / dataCollector / Collector / allRooms . py
 

感觉明明没有问题,可脚本为什么不执行呢,思考一下,由于是在虚拟环境中运行,直接通过python+脚本文件的方式,使用的python解译器是系统中的python而不是虚拟环境中的那个。所以上边的crontab配置改成这样就可以顺利运行了:

Python
0,15,30,45 * * * * /home/eclipse/git/env/bin/python /home/eclipse/git/env/DouyuFan/app/dataCollector/Collector/allRooms.py
1
2
0 , 15 , 30 , 45 * * * * / home / eclipse / git / env / bin / python / home / eclipse / git / env / DouyuFan / app / dataCollector / Collector / allRooms . py
 

关于python学习相关的想法

由于自己缺乏在实际生产环境中的工作经验,这方面知识有很大一部分欠缺。只能通过自己慢慢摸索。另外,看了前几天刚买的python cookbook之后,感觉像是进入了python的新世界,有很多方法和内容都是之前没有尝试过的,未来要走的路还有很长,加油!




  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值