折腾:
【已解决】把Python3的pipenv的Flask部署到CentOS服务器上
期间,先去Mac本地中,折腾用gunicorn去部署和启动Flask应用。
Gunicorn deploy flask
How To Serve Flask Applications with Gunicorn and Nginx on Ubuntu 16.04 | DigitalOcean
Deploy flask app with nginx using gunicorn and supervisor
Flask + Gunicorn + Nginx 部署 – Ray Liang – 博客园
Deploy Flask Applications with Gunicorn and Nginx on Ubuntu 14.04
How to setup Flask with gunicorn and nginx with example | Tech Tutorials
Flask Gunicorn Supervisor Nginx 项目部署小总结
然后先去折腾简单的gunicorn
等熟悉了后,再去放到supervisor中
先去安装:
<code>➜ robotDemo pipenv install gunicorn Installing gunicorn… Collecting gunicorn Downloading https://files.pythonhosted.org/packages/64/32/becbd4089a4c06f0f9f538a76e9fe0b19a08f010bcb47dcdbfbc640cdf7d/gunicorn-19.7.1-py2.py3-none-any.whl (111kB) Installing collected packages: gunicorn Successfully installed gunicorn-19.7.1 Adding gunicorn to Pipfile's [packages]… Pipfile.lock (36c54e) out of date, updating to (cdbe9e)… Locking [dev-packages] dependencies… Locking [packages] dependencies… Updated Pipfile.lock (cdbe9e)! Installing dependencies from Pipfile.lock (cdbe9e)… 🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 13/13 — 00:00:03 To activate this project's virtualenv, run the following: $ pipenv shell ➜ robotDemo pipenv graph Flask-PyMongo==0.5.1 - Flask [required: >=0.8, installed: 0.12.2] - click [required: >=2.0, installed: 6.7] - itsdangerous [required: >=0.21, installed: 0.24] - Jinja2 [required: >=2.4, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - Werkzeug [required: >=0.7, installed: 0.14.1] - PyMongo [required: >=2.5, installed: 3.6.1] Flask-RESTful==0.3.6 - aniso8601 [required: >=0.82, installed: 3.0.0] - Flask [required: >=0.8, installed: 0.12.2] - click [required: >=2.0, installed: 6.7] - itsdangerous [required: >=0.21, installed: 0.24] - Jinja2 [required: >=2.4, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - Werkzeug [required: >=0.7, installed: 0.14.1] - pytz [required: Any, installed: 2018.4] - six [required: >=1.3.0, installed: 1.11.0] gunicorn==19.7.1 </code>
现在本地Mac中,先进入pipenv的虚拟环境中:
<code>➜ robotDemo pipenv shell Spawning environment shell (/bin/zsh). Use 'exit' to leave. . /Users/crifan/.local/share/virtualenvs/robotDemo-HXjMJQEQ/bin/activate ➜ robotDemo . /Users/crifan/.local/share/virtualenvs/robotDemo-HXjMJQEQ/bin/activate ➜ robotDemo which gunicorn /Users/crifan/.local/share/virtualenvs/robotDemo-HXjMJQEQ/bin/gunicorn ➜ robotDemo gunicorn --version gunicorn (version 19.7.1) </code>
再去运行试试,运行之前,先去搞清楚gunicorn的参数的含义:
【已解决】部署Flask的gunicorn的最后一个参数的含义
而在看help信息期间:
待会抽空试试reload参数
注意到–chdir CHDIR,默认是当前目录:
/Users/crifan/dev/dev_root/company/naturling/projects/robotDemo
然后就是先去命令行中试试:
<code>➜ robotDemo gunicorn -w 4 -b 127.0.0.1:32851 app:app [2018-04-20 11:56:43 +0800] [2640] [INFO] Starting gunicorn 19.7.1 [2018-04-20 11:56:43 +0800] [2640] [INFO] Listening at: http://127.0.0.1:32851 (2640) [2018-04-20 11:56:43 +0800] [2640] [INFO] Using worker: sync [2018-04-20 11:56:43 +0800] [2643] [INFO] Booting worker with pid: 2643 [2018-04-20 11:56:43 +0800] [2644] [INFO] Booting worker with pid: 2644 [2018-04-20 11:56:43 +0800] [2645] [INFO] Booting worker with pid: 2645 [2018-04-20 11:56:43 +0800] [2646] [INFO] Booting worker with pid: 2646 [2018-04-20 11:56:43,624 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x10536a780> [2018-04-20 11:56:43,626 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x104f69710> [2018-04-20 11:56:43,629 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 11:56:43,629 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 11:56:43,670 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x10576a7f0> [2018-04-20 11:56:43,673 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 11:56:43,702 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x1065feef0> [2018-04-20 11:56:43,704 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') </code>
然后去GET测试一下:
gunicorn中输出对应的log:
<code>[2018-04-20 11:57:13,018 INFO app.py:104 get] parser=<flask_restful.reqparse.RequestParser object at 0x10622e0f0> [2018-04-20 11:57:13,021 INFO app.py:107 get] parsedArgs={'q': 'play a morning song'} [2018-04-20 11:57:13,024 INFO app.py:113 get] q=play a morning song [2018-04-20 11:57:13,026 INFO app.py:122 get] foundSongName=<_sre.SRE_Match object; span=(0, 19), match='play a morning song'> [2018-04-20 11:57:13,029 INFO app.py:128 get] songName=morning [2018-04-20 11:57:13,031 INFO app.py:150 get] filenameRegex=re.compile('morning', re.IGNORECASE) [2018-04-20 11:57:13,032 INFO app.py:156 get] findFileCursor=<gridfs.grid_file.GridOutCursor object at 0x10622e358> [2018-04-20 11:57:13,197 INFO app.py:158 get] findFileCount=0 </code>
在搞定了命令行之后,去参考:
“* -D, –daemon
以守护进程形式来运行Gunicorn进程,其实就是将这个服务放到后台去运行。
配置文件必须是一个python文件,只是将命令行中的参数写进py文件中而已,如果需要设置哪个参数,则在py文件中为该参数赋值即可。”
去换成配置文件,然后多加点参数,看看效果。还不错:
配置文件:
gunicorn_config.py
<code>import multiprocessing currentRootPath = "/Users/crifan/dev/dev_root/company/naturling/projects/robotDemo" reload = True #当代码改变时自动重启服务 bind = '127.0.0.1:32851' #绑定ip和端口号 backlog = 512 #监听队列 chdir = currentRootPath #gunicorn要切换到的目的工作目录 timeout = 30 #超时 worker_class = 'sync' #默认的是sync模式 workers = multiprocessing.cpu_count() * 2 + 1 #进程数 threads = 2 #指定每个进程开启的线程数 loglevel = 'info' #日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置 access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' #设置gunicorn访问日志格式,错误日志无法设置 """ 其每个选项的含义如下: h remote address l '-' u currently '-', may be user name in future releases t date of the request r status line (e.g. ``GET / HTTP/1.1``) s status b response length or '-' f referer a user agent T request time in seconds D request time in microseconds L request time in decimal seconds p process ID """ accesslog = currentRootPath + "/logs/gunicorn_access.log" #访问日志文件 errorlog = currentRootPath + "/logs/gunicorn_error.log" #错误日志文件 </code>
然后去调用:
<code>gunicorn -c gunicorn_config.py app:app </code>
输出效果是:
<code> robotDemo gunicorn -c gunicorn_config.py app:app [2018-04-20 13:45:16,938 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae89e8> [2018-04-20 13:45:16,945 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,087 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae7978> [2018-04-20 13:45:17,094 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,116 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae8a58> [2018-04-20 13:45:17,122 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,253 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae8ac8> [2018-04-20 13:45:17,262 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,361 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae8b38> [2018-04-20 13:45:17,367 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,387 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae8c18> [2018-04-20 13:45:17,392 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,393 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae8ba8> [2018-04-20 13:45:17,399 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,405 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111ae9c88> [2018-04-20 13:45:17,426 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') [2018-04-20 13:45:17,428 INFO app.py:59 <module>] api=<flask_restful.Api object at 0x111aeacf8> [2018-04-20 13:45:17,431 INFO app.py:80 <module>] purePymongo=MongoClient(host=['47.96.131.109:32018'], document_class=dict, tz_aware=False, connect=True, authsource='gridfs') </code>
其中可见,worker=9=4(CPU个数) * 2 + 1
同时试试:
<code>--reload Restart workers when code changes. [False] </code>
参数,还真是可以实现:
改动之前效果:
当代码改动:
自动重启服务,然后有新的GET后可以输出的刚刚代码改动后的新的效果了:
同时看看log输出效果:
【总结】
此处,对于Mac本地的pipenv的虚拟环境中使用gunicorn去部署Flask的应用,做法是:
1.pipenv中安装gunicorn
<code>pipenv install gunicorn </code>
2.命令行中直接调用
<code>gunicorn -w 4 -b 127.0.0.1:32851 app:app </code>
其中:
-w=–worker=进程数
-b=–bind=监听的地址和端口
app:app:
第一个app:指的是此处的app.py
ls -l
-rw-r–r– 1 crifan staff 8.3K 4 20 13:46 app.py
第二个app:指的是(app.py中的)Flask的实例的名字叫做app
app = Flask(__name__)
3.也可以用配置文件去调用
gunicorn_config.py
<code>import multiprocessing currentRootPath = "/Users/crifan/dev/dev_root/company/naturling/projects/robotDemo" reload = True #当代码改变时自动重启服务 bind = '127.0.0.1:32851' #绑定ip和端口号 backlog = 512 #监听队列 chdir = currentRootPath #gunicorn要切换到的目的工作目录 timeout = 30 #超时 worker_class = 'sync' #默认的是sync模式 workers = multiprocessing.cpu_count() * 2 + 1 #进程数 threads = 2 #指定每个进程开启的线程数 loglevel = 'info' #日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置 access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' #设置gunicorn访问日志格式,错误日志无法设置 """ 其每个选项的含义如下: h remote address l '-' u currently '-', may be user name in future releases t date of the request r status line (e.g. ``GET / HTTP/1.1``) s status b response length or '-' f referer a user agent T request time in seconds D request time in microseconds L request time in decimal seconds p process ID """ accesslog = currentRootPath + "/logs/gunicorn_access.log" #访问日志文件 errorlog = currentRootPath + "/logs/gunicorn_error.log" #错误日志文件 </code>
调用方式:
<code>gunicorn -c gunicorn_config.py app:app </code>
即可。
其中指定了输出的access和error的log。
备注1:
从:
“日志配置参数,命令行中使用 –access-logfile ,而在文件配置中使用 accesslog。”
-》刚刚自己也是注意到:
命令行参数是
<code> --error-logfile FILE, --log-file FILE The Error log file to write to. [-] </code>
而配置文件中的是:
<code>accesslog </code>
详见:Settings — Gunicorn 19.7.1 documentation
备注2:
刚才参考别人配置时,就把worker_class从gevent换成了sync
否则需要我去安装gevent
然后看到:
Flask+Gunicorn+Gevent+Supervisor+Nginx生产环境部署-xujpxm-51CTO博客
“3). gevent:把Python同步代码变成异步协程的库;
-k: 指定worker-class模式,默认为sync,这里用gevent使之变为异步协程,提高性能。”
-》所以:
如果后续需要把同步换异步,再去考虑把gunicorn的worker_class从sync换gevent
转载请注明:在路上 » 【已解决】Mac本地用gunicorn部署启动Flask应用