Flask应用示例3 - 通过nginx+gunicorn+flask搭建web服务

1,目的

在生产环境下,可以通过Nginx+gunicorn+Flask部署Web服务,从而达到高并发高稳定性的要求。
如果要部署多个APP,可以采用单个Nginx,多个gunicorn+Flask的方式来实现,如下图所示。

gunicorn.png

此外,还可以参考本人的上篇文章,通过nginx+uwsgi+flask搭建web服务

通过两个模式的搭建,个人感觉gunicorn与nginx只是通过端口做反向代理,不像uwsgi通过pid进行通信,效率可能受到影响,没有uwsgi高(并没有大数据量的测试)。
但是,gunicorn用着更顺手,本身就是通过python开发的,可以通过配置文件执行钩子代码(支持python),例如请求前后的处理等等。

2,安装过程

2.1,升级软件包

sudo apt-get update 

2.2,安装virtualenv和python环境

sudo apt-get install build-essential python-dev python-pip 
sudo pip install virtualenv

2.3,在virtualenv中部署flask app,并测试

  • 创建存放网站的目录
mkdir mysite
  • 配置virtualenv和安装flask

进入mysite目录,然后创建虚拟环境.my_env,激活虚拟环境,然后安装flask

cd mysite 
virtualenv .my_env           # 创建Python虚拟环境
source .my_env/bin/activate  # 进入Python虚拟环境,退出命令是deactivate
pip install flask            # 在虚拟环境下安装flask
  • 保存虚拟环境的Python包到requirements.txt
# 通过pip freeze保存Python第三方包到requirement文件里面,既能知道自己安装了什么库,也方便别人部署时,安装相应的库。
pip freeze > requirements.txt
  • 在mysite目录下创建hello.py
from flask import Flask
app = Flask(__name__)

@app.route("/app1/")
def hello():
    return "Hello World!"

@app.route("/app1/flask/")
def hello_flask():
    return "Hello World! Hello Flask!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)

需要注意的是,app.run()只是开发时测试使用,故需要放置在if __name__ == "__main__"下,这样gunicorn才不会执行app.run()方法。而host需要设置为0.0.0.0,表示让flask监听机器的所有ip地址的8080端口。

  • 启动测试
    执行以下命令,可以启动Flask。通过浏览器访问192.168.1.32:8080/app1/,如果返回“Hello World!”,则证明启动OK。
python hello.py

2.4,在virtualenv中部署gunicorn,并测试

  • 进入到Python虚拟环境,并安装gunicorn
source .env/bin/activate  # 进入Python虚拟环境,退出命令是deactivate
pip install gunicorn      # 在虚拟环境中安装gunicorn
  • 在虚拟环境下,直接启动gunicorn
# -w 表示开启多少个worker,根据系统核心数确定,-b表示gunicorn开放的访问地址
(.my_env) kevin@black:~/test$ gunicorn -w 8 -b 0.0.0.0:30000 hello:app
[2017-11-23 19:50:37 +0000] [3725] [INFO] Starting gunicorn 19.7.1
[2017-11-23 19:50:37 +0000] [3725] [INFO] Listening at: http://0.0.0.0:30000 (3725)
[2017-11-23 19:50:37 +0000] [3725] [INFO] Using worker: sync
[2017-11-23 19:50:37 +0000] [3731] [INFO] Booting worker with pid: 3731
[2017-11-23 19:50:37 +0000] [3732] [INFO] Booting worker with pid: 3732
[2017-11-23 19:50:37 +0000] [3737] [INFO] Booting worker with pid: 3737
[2017-11-23 19:50:37 +0000] [3740] [INFO] Booting worker with pid: 3740
[2017-11-23 19:50:37 +0000] [3743] [INFO] Booting worker with pid: 3743
[2017-11-23 19:50:37 +0000] [3744] [INFO] Booting worker with pid: 3744
[2017-11-23 19:50:38 +0000] [3749] [INFO] Booting worker with pid: 3749
[2017-11-23 19:50:38 +0000] [3750] [INFO] Booting worker with pid: 3750

# -k gevent,worker_class进程的工作方式,默认是sync,gevent需要提前安装,可选值eventlet、gevent、tornado、gthread、giohttp

# 查看进程,可以看到用到了虚拟环境的包,否则用的是全局的包
kevin@black:~$ ps -ef | grep gunicorn
kevin  3725 21793  1 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3731  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3732  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3737  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3740  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3743  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3744  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3749  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3750  3725  0 19:50 pts/11   00:00:00 /home/kevin/test/.my_env/bin/python /home/kevin/test/.my_env/bin/gunicorn -w 8 -b 0.0.0.0:30000 hello:app
kevin  3839   937  0 19:50 pts/12   00:00:00 grep --color=auto gunicorn

# 关闭进程
pkill gunicorn

2.5,安装nginx,并配置测试

  • 安装nginx(不在python虚拟环境下)
sudo apt-get install nginx
  • 编辑配置文件:/etc/nginx/conf.d/gunicorn.conf
server {
    listen 8000;
    server_name example.org; # 这是HOST机器的外部域名,用地址也行

    location / {
        proxy_pass http://192.168.1.30:30000; # 这里是指向 gunicorn host 的服务地址
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • nginx启动测试
kevin@orange:~/web/flask/mysite$ sudo service nginx start
kevin@orange:~/web/flask/mysite$ ps -ef | grep nginx
root      2324     1  0 16:19 ?        00:00:00 nginx: master process /usr/sbin/nginx
www-data  2325  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2326  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2327  2324  0 16:19 ?        00:00:00 nginx: worker process
www-data  2328  2324  0 16:19 ?        00:00:00 nginx: worker process
zhangsh+  2330  2171  0 16:20 pts/1    00:00:00 grep --color=auto nginx

2.6,服务测试

  • Http访问测试,一切OK
kevin@Blue:~$ curl http://192.168.1.32:81/app1/flask/
Hello World! Hello Flask!
kevin@Blue:~$ curl http://192.168.1.32:81/app1/
Hello World!
  • 浏览器访问测试,一切OK
test 1.png
test 2.png

3,gunicorn高级用法

  • 在虚拟环境中,安装gevent
pip install gevent
#coding=utf-8
import os
bind = '127.0.0.1:8422'  #绑定的ip已经端口号
workers = 8              #进程数
threads = 2              #指定每个进程开启的线程数,官方推荐设置为核心数的两至四倍
backlog = 2048           #允许挂起的连接数的最大值,官方推荐这个值设在64-2048
timeout = 30             #超时时间,单位秒
worker_class = "gevent"  #工作方式,使用gevent模式,默认的是sync模式(并发只有1个),可选值eventlet、gevent、tornado、gthread、giohttp
worker_connections=1000  #进程链接数,默认值1000,同时链接客户端的阀值,这个设置只对进程工作方式为Eventlet和Gevent的产生影响
daemon=True              #守护进程,默认值是False,守护进程形式来运行Gunicorn进程
pidfile='gunicorn.pid'      #设置pid文件的文件名,如果不设置的话,不会创建pid文件,默认值是None
proc_name="myflask"      #默认值default_proc_name,即gunicorn(需要额外安装setproctitle),但是测试没有生效,需要深入看看??
pythonpath='/home/kevin/test/.my_env/bin'  # 将这些路径加到python path去

loglevel='info'         #日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置,可以是debug,info,warning,error,critical
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'     #设置gunicorn访问日志格式,错误日志无法设置
accesslog = "/home/kevin/test/log/access.log"   #访问日志文件的路径
errorlog = "/home/kevin/test/log/error.log"    #错误日志文件的路径
# accesslog = "log/access.log"   #访问日志文件的路径
# errorlog = "log/error.log"     #错误日志文件的路径

# debug = False
# chdir = '/home/lijiajia/Ip_Asnproject/AsnProc'   #gunicorn要切换到的目的工作目录,测试后,没搞懂具体含义???

# 可以通过以下包完成对gunicorn日志的按天分割,具体用的时候可以尝试
# import logging
# import logging.handlers
# from logging.handlers import WatchedFileHandler

4,参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容