你好!歡迎閱讀個人博文,你能夠跳轉到個人我的博客網站,會有更好的排版效果和功能。
此外,本篇博文爲本人Pushy原創,如需轉載請註明出處:https://pushy.site/posts/1519817202html
我在不少的博客中都看過有關Flask
應用的部署,也有不少博主在開博後都記錄了部署的教程,由於其中的坑能夠說很多。一開始我在網上看到相比較與Ubuntu
,CentOS
由於更新少做爲服務器的操做系統會更加穩定。因此在第一次購買雲服務器時,我選擇了CentOS
,後來因爲CentOS
不一樣發行版的Nginx
緣故,我又換成了Ubuntu
的鏡像前端
首先呢,咱們先來了解下關於Web服務器與Web應用還有WSGI之間的聯繫python
WSGI
(Web Server Gateway Interface),翻譯爲Python web
服務器網關接口,即Python
的Web
應用程序(如Flask
)和Web
服務器(如Nginx
)之間的一種通訊協議。也就是說,若是讓你的Web
應用在任何服務器上運行,就必須遵循這個協議。nginx
那麼實現WSGI
協議的web服務器有哪些呢?就好比uWSGI
與gunicorn
。二者均可以做爲Web服務器。可能你在許多地方看到的都是採用Nginx
+ uWSGI
(或gunicorn
)的部署方式。實際上,直接經過uWSGI
或gunicorn
直接部署也是可讓外網訪問的,那你可能會說,那要Nginx
何用?別急,那麼接來下介紹另外一個Web服務器——Nginx
git
Nginx
做爲一個高性能Web服務器,具備負載均衡、攔截靜態請求、高併發...等等許多功能,你可能要問了,這些功能和使用Nginx
+ WSGI
容器的部署方式有什麼關係?github
首先是負載均衡,若是你瞭解過OSI模型的話,其實負載均衡器就是該模型中4~7層交換機中的一種,它的做用是可以僅經過一個前端惟一的URL訪問分發到後臺的多個服務器,這對於併發量很是大的企業級Web站點很是有效。在實際應用中咱們一般會讓Nginx
監聽(綁定)80
端口,經過多域名或者多個location分發到不一樣的後端應用。web
其次是攔截靜態請求,簡單來講,Nginx
會攔截到靜態請求(靜態文件,如圖片),並交給本身處理。而動態請求內容將會經過WSGI
容器交給Web
應用處理;flask
Nginx
還有其餘不少的功能,這裏便不一一介紹。那麼前面說了,直接經過uWSGI
或gunicorn
也可讓外網訪問到的,可是鑑於Nginx
具備高性能、高併發、靜態文件緩存、及以上兩點、甚至還能夠作到限流與訪問控制,因此選擇Nginx
是頗有必要的;後端
這裏能夠說明,若是你選擇的架構是:Nginx + WSGI容器 + web應用,WSGI容器至關於一箇中間件;若是選擇的架構是uWSGI + web應用,WSGI容器則爲一個web服務器瀏覽器
該篇部署的教程是在你已經購買好虛擬主機,而且已經搭建好開發環境的前提下進行的,若是你尚未搭建好開發環境,能夠參考我寫的文檔:
廣泛的部署方式都是經過讓Nginx
綁定80
端口,並接受客戶端的請求將動態內容的請求反向代理給運行在本地端口的uWSGI
或者Gunicorn
,因此既能夠經過Nginx
+ uWSGI
也能夠經過Nginx
+ Gunicorn
來部署Flask
應用,這篇教程中都將一一介紹這兩種方法
固然採用不一樣的WSGI
容器,Nginx
中的配置也會有所不一樣
咱們如今虛擬環境下安裝好uWSGI
:
(venv) $ pip install uwsgi
安裝完成以後咱們在項目的目錄下(即你實際建立的Flask項目目錄,在本文所指的項目目錄都假設爲/www/demo)建立以.ini
爲擴展名的配置文件。在設置與Nginx
交互的時候有兩種方式:
第一種是經過配置網絡地址,第二種是經過本地的.socket
文件進行通訊。須要注意的是,不一樣的交互方式下,Nginx
中的配置也會有所不一樣
若是採用的是第一種網絡地址的方式,則將以前建立uwsgi.ini
配置文件添加以下的配置內容:
[uwsgi] socket = 127.0.0.1:8001 //與nginx通訊的端口 chdir = /www/demo/ //你的Flask項目目錄 wsgi-file = run.py callable = app //run.py文件中flask實例化的對象名 processes = 4 //處理器個數 threads = 2 //線程個數 stats = 127.0.0.1:9191 //獲取uwsgi統計信息的服務地址
這裏的wsgi-file
參數所指的run.py
實際上是啓動文件,你也可使用manage.py
。不過我一般習慣建立一個這樣的文件,能夠直接運行該文件來啓動項目:
from app import app if __name__ == '__main__': app.run()
保存好配置文件後,就能夠經過以下的命令來啓動應用了:
(venv) $ uwsgi uwsig.ini
若是你採用的是第二種本地socket
文件的方式,則添加以下的配置內容:
[uwsgi] socket = /www/demo/socket/nginx_uwsgi.socket //與nginx通訊的socket文件 chdir = /www/demo/ wsgi-file = run.py callable = app processes = 4 threads = 2 stats = 127.0.0.1:9191
能夠看到,其實與網絡地址的配置方式只有socket
參數的配置不一樣,在這裏填寫好路徑名和文件名並啓動uWSGI
後,將會自動在改目錄下生成nginx_uwsgi.socket
文件,這個文件就是用來與Nginx
交互的。
首先咱們來經過apt
安裝Nginx
:
$ sudo apt-get install nginx
安裝完成以後,咱們cd
到/etc/nginx/
的目錄下(可能因爲不一樣系統致使不一樣的Nginx發行版緣故,目錄有所差異,在此只針對Ubuntu
中的發行版的Nginx),能夠看到Nginx
的全部配置文件。
其中nginx.conf
文件爲主配置文件,能夠用來修改其全局配置;sites-available
存放你的配置文件,可是在這裏添加配置是不會應用到Nginx
的配置當中,須要軟鏈接到同目錄下的sites-enabled
當中。可是在我實際操做的過程當中中,當我在sites-available
修改好配置文件後,會自動更新到sites-enabled
。若是沒有的話,則須要像上述的操做那樣,將修改好的配置文件軟連接到sites-enabled
當中
在上邊說到,配置uWSGI
有兩種與Nginx
交互的方式,那麼選擇不一樣的方式的話在Nginx
的配置也會有所不一樣:
第一種:網絡配置方式:
這裏的proxy_set_header
設置的三個參數的做用都是可以直接得到到客戶端的IP
,若是你感興趣能夠參考:Nginx中proxy_set_header 理解
用include uwsgi_params
導入uWSGI
所引用的參數,經過uwsgi_pass
反向代理給在localhost:8001
運行的uWSGI
:
server { listen 80; # 監聽的端口號 root /www/demo; #Flask的項目目錄 server_name xxx.xx.xxx.xxx; # 你的公網ip或者域名 location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; include uwsgi_params; uwsgi_pass localhost:8001; } # 配置static的靜態文件: location ~ ^\/static\/.*$ { root /www/demo; # 注意!這裏不須要再加/static了 } }
在每次完Nginx配置文件內容後,須要經過以下的命令來重啓Nginx:
$ nginx -s reload
第二種:socket文件方式:
與上邊的配置內容大致相同,只是在配置uwsgi_pass
不是反向代理給網絡地址,而是經過socket
文件進行交互,咱們只須要指定以前設置的路徑和文件名便可:
server { listen 80; root /www/demo; server_name xxx.xx.xxx.xxx; location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; include uwsgi_params; uwsgi_pass unix:/www/demo/socket/nginx_uwsgi.socket; } location ~ ^\/static\/.*$ { root /www/demo; } }
首先先在虛擬環境下安裝Gunicorn
:
(venv) $ pip install gunicorn
安裝完成後,咱們來建立以.py
結尾的配置文件,這裏我參考了Jiyuankai的GitHub關於Gunicorn
的配置文件內容:
from gevent import monkey monkey.patch_all() import multiprocessing debug = True loglevel = 'debug' bind = '127.0.0.1:5000' //綁定與Nginx通訊的端口 pidfile = 'log/gunicorn.pid' logfile = 'log/debug.log' workers = multiprocessing.cpu_count() * 2 + 1 worker_class = 'gevent' //默認爲阻塞模式,最好選擇gevent模式
須要注意的是要在配置文件的同層目錄下建立log
文件,不然運行gunicorn
將報錯。添加完配置內容並保存爲gconfig.py
文件後,咱們就也能夠經過gunicorn
來運行Flask
應用了:
(venv)$ gunicorn -c /www/demo/gconfig.py run:app
和uWSGI
的任意一種配置方法相似,只是在location
中的配置有所不一樣:
server { listen 80; root /www/demo; server_name xxx.xx.xxx.xxx; location / { proxy_set_header x-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://localhost:5000/; # gunicorn綁定的端口號 } # 配置static的靜態文件: location ~ ^\/static\/.*$ { root /www/demo; } }
經過Gunicorn的Nginx配置中,咱們只須要經過proxy_pass
參數反向代理給運行在http://localhost:5000/
上的Gunicorn
若是你採起如上的任意一種部署方式,在Nginx與uWSGI或Gunicorn同時運行,而且配置無誤的狀態下,那麼你如今應該是能夠經過你的公網ip
或者域名訪問到你的網站了。
可是還有一個問題,到目前爲止,uWSGI和gunicorn都是直接經過命令行運行,並不可以在後臺運行,也是當咱們關閉了xShell(或者你使用的是Putty及其餘SSH鏈接的軟件),將沒法再訪問到你的應用。因此咱們須要讓uWSGI或gunicorn在後臺運行,也就是所謂的daemon(守護進程)。
若是你熟悉Linux命令,你應該知道在Linux中後臺運行能夠經過nohup
命令,例如咱們要讓gunicorn在後臺運行,咱們只須要運行nohup
命令:
(venv) $ nohup gunicorn -c gconfig.py run:app &
運行後你能夠經過ps -e | grep gunicorn
指令來查看到當前gunicorn的運行狀態:
若是你選擇的是uWSGI,一樣也能夠經過nohup
命令來實現守護進程:
(venv) $ nohup uwsgi uwsgi.ini &
這樣你就能夠關閉鏈接服務器的終端,還能經過你的瀏覽器訪問到你的Flask
應用了!
可是nohup
運行的後臺程序並不可以可靠的在後臺運行,咱們最好讓咱們的後臺程序可以監控進程狀態,還能在乎外結束時自動重啓,這就可使用一個使用Python開發的進程管理程序supervisor。
首先咱們經過apt
來安裝supervisor:
$ sudo apt-get install supervisor
安裝完成後,咱們在/etc/supervisor/conf.d/
目錄下建立咱們控制進程的配置文件,並以.conf結尾,這樣將會自動應用到主配置文件當中,建立後添加以下的配置內容:
[program:demo] command=/www/demo/venv/bin/gunicorn -c /pushy/blog/gconfig.py run:app directory=/www/demo //項目目錄 user=root autorestart=true //設置自動重啓 startretires=3 //重啓失敗3次
在上面的配置文件中,[program:demo]
設置了進程名,這與以後操做進程的狀態名稱有關,爲demo
;command
爲進程運行的命令,必須使用絕對路徑,而且使用虛擬環境下的gunicorn
命令;user
指定了運行進程的用戶,這裏設置爲root
保存配置文件以後,咱們須要經過命令來更新配置文件:
$ supervisorctl update
命令行將顯示:demo: added process group
,而後咱們來啓動這個demo
進程:
$ supervisorctl start demo
固然你也直接在命令行輸入supervisorctl
進入supevisor的客戶端,查看到當前的進程狀態:
demo RUNNING pid 17278, uptime 0:08:51
經過stop
命令即可以方便的中止該進程:
supervisor> stop demo
參考資料: