使用gunicorn部署flask專案
1、WSGI協議
Web框架致力於如何生成HTML程式碼,而Web伺服器用於處理和響應HTTP請求。Web框架和Web伺服器之間的通訊,需要一套雙方都遵守的介面協議。WSGI協議就是用來統一這兩者的介面的。
2、WSGI容器
常用的WSGI容器有Gunicorn和uWSGI,但Gunicorn直接用命令啟動,不需要編寫配置檔案,相對uWSGI要容易很多,所以這裡我也選擇用Gunicorn作為容器。
3、gunicorn介紹
gunicorn是一個python Wsgi http server,只支援在Unix系統上執行,來源於Ruby的unicorn專案。Gunicorn使用prefork master-worker模型(在gunicorn中,master被稱為arbiter),能夠與各種wsgi web框架協作。
4、gunicorn安裝
gunicorn安裝非常簡單,使用命令pip install gunicorn即可。一般使用它,主要是為使用其非同步的worker模型,還需要安裝對應的非同步模組。
$ pip install greenlet # 使用非同步必須安裝 $ pip install eventlet # 使用eventlet workers $ pip install gevent # 使用gevent workers
5、gunicorn使用
這裡使用gunicorn來部署一個flask專案舉例,此處flask框架的使用不過多闡述,不是本文的重點。
如下例子,儲存為app.py
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!"
通過gunicorn -h
可以看到gunicorn有非常多的配置項,因此通常會寫成一個config.py檔案來進行配置。
# config.py import os import gevent.monkey gevent.monkey.patch_all() import multiprocessing # debug = True loglevel = 'debug' bind = "0.0.0.0:7001" pidfile = "log/gunicorn.pid" accesslog = "log/access.log" errorlog = "log/debug.log" daemon = True # 啟動的程序數 workers = multiprocessing.cpu_count() worker_class = 'gevent' x_forwarded_for_header = 'X-FORWARDED-FOR'
1. debug = True
生產環境不需要這個配置項,但除錯的時候還是挺好用的。而且,開啟debug項後,在啟動gunicorn的時候可以看到所有可配置項的配置,如下所示。之前在被上一篇博主欺騙的時候,仔細看了除錯資訊,發現accesslog和errorlog都沒有被配置,所以導致啟動以後看不到任何日誌。 config.py中只需要配置需要修改的項的,大部分採用預設配置即可。預設配置的具體配置內容可以通過
gunicorn -h
來查詢。
# Debug Info [2018-01-18 17:38:47 +0000] [16015] [DEBUG] Current configuration: proxy_protocol: False worker_connections: 1000 statsd_host: None max_requests_jitter: 0 post_fork: <function post_fork at 0x21037d0> errorlog: - enable_stdio_inheritance: False worker_class: gunicorn.workers.ggevent.GeventWorker ssl_version: 2 suppress_ragged_eofs: True syslog: False syslog_facility: user when_ready: <function when_ready at 0x2103500> pre_fork: <function pre_fork at 0x2103668> cert_reqs: 0 preload_app: False keepalive: 2 accesslog: log/debug.log group: 1001 graceful_timeout: 30 do_handshake_on_connect: False spew: False workers: 2 proc_name: None sendfile: None pidfile: log/gunicorn.pid umask: 0 on_reload: <function on_reload at 0x2103398> pre_exec: <function pre_exec at 0x2103d70> worker_tmp_dir: None limit_request_fields: 100 pythonpath: None on_exit: <function on_exit at 0x21065f0> config: gunicorn_conf.py logconfig: None check_config: False statsd_prefix: secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'} reload_engine: auto proxy_allow_ips: ['127.0.0.1'] pre_request: <function pre_request at 0x2103ed8> post_request: <function post_request at 0x2106050> forwarded_allow_ips: ['127.0.0.1'] worker_int: <function worker_int at 0x2103aa0> raw_paste_global_conf: [] threads: 1 max_requests: 0 chdir: /home/hzyangxiao2014/POPORobot/QASP daemon: False user: 1028 limit_request_line: 4094 access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" certfile: None on_starting: <function on_starting at 0x2103230> post_worker_init: <function post_worker_init at 0x2103938> child_exit: <function child_exit at 0x21061b8> worker_exit: <function worker_exit at 0x2106320> paste: None default_proc_name: run:app syslog_addr: udp://localhost:514 syslog_prefix: None ciphers: TLSv1 worker_abort: <function worker_abort at 0x2103c08> loglevel: debug bind: ['0.0.0.0:7001'] raw_env: [] initgroups: False capture_output: False reload: False limit_request_field_size: 8190 nworkers_changed: <function nworkers_changed at 0x2106488> timeout: 30 keyfile: None ca_certs: None tmp_upload_dir: None backlog: 2048 logger_class: gunicorn.glogging.Logger
2. 日誌
# config.py accesslog = "log/access.log" errorlog = "log/debug.log" loglevel = "debug"
- 需要log目錄存在。如果不存在,啟動會報錯
- accesslog是訪問日誌,可以通過access_log_format設定訪問日誌格式。詳細的方法可以見參考文章[2]
- loglevel用於控制errorlog的資訊級別,可以設定為debug、info、warning、error、critical。
3. workers
worker_class是指開啟的每個工作程序的模式型別,預設為sync模式,也可使用gevent模式。
workers
是工作程序數量,在上述config.py
中,取的是CPU的數量。需要注意部署機器的效能,不能無限制多開。多篇文章中推薦了multiprocessing.cpu_count() * 2 + 1
這個數量,考慮到我會在一個機器上部署兩個服務,因此數量減半。
4. daemon
daemon = True
意味著開啟後臺執行,預設為False
gunicorn通常使用的引數如下:
-c CONFIG, --config=CONFIG # 設定配置檔案。 -b BIND, --bind=BIND # 設定服務需要繫結的埠。建議使用HOST:PORT。 -w WORKERS, --workers=WORKERS # 設定工作程序數。建議伺服器每一個核心可以設定2-4個。 -k MODULE # 選定非同步工作方式使用的模組。
在shell中輸入你的啟動配置,比如:
$ gunicorn -w 3 -b 127.0.0.1:8080 app:app # 此處app:app中,第一個app為flask專案例項所在的包,第二個app為生成的flask專案例項
這樣執行正常就可以啟動伺服器了。
6、繫結埠
linux通常會禁止繫結使用1024以下的埠,除非在root使用者許可權。很多人在使用gunicorn時試圖將其繫結到80或者443埠,發現無效。如果想繫結到這些埠,常見的有如下的幾種方法:
- 使用Nginx代理轉發。
- sudo啟動gunicorn。
- 安裝額外的程式。
7、結束gunicorn服務程序
使用ps -ef | grep gunicorn命令找出gunicorn所有程序。
[root@VM_0_12_centos ~]# ps -ef | grep gunicorn root 16843 23035 0 Oct14 ? 00:00:02 /root/Envs/myflask/bin/python3.6 /root/Envs/myflask/bin/gunicorn -w 3 -b 172.17.0.12:80 app:app root 22445 23035 0 Oct04 ? 00:00:15 /root/Envs/myflask/bin/python3.6 /root/Envs/myflask/bin/gunicorn -w 3 -b 172.17.0.12:80 app:app root 22581 23035 0 Oct11 ? 00:00:05 /root/Envs/myflask/bin/python3.6 /root/Envs/myflask/bin/gunicorn -w 3 -b 172.17.0.12:80 app:app root 23035 1 0 Sep27 ? 00:04:11 /root/Envs/myflask/bin/python3.6 /root/Envs/myflask/bin/gunicorn -w 3 -b 172.17.0.12:80 app:app
然後使用 kill -9 程序ID 命令來殺掉程序,注意,我們找到主程序殺掉即可,子程序會隨之結束,在上例中,主程序號為23035.
[root@VM_0_12_centos ~]# kill -9 23035 [root@VM_0_12_centos ~]# ps -ef | grep gunicorn
殺掉程序後,稍等幾秒,再使用ps -ef | grep gunicorn檢視,發現gunicorn服務程序已全部殺掉。