如何使用Nginx和uWSGI或Gunicorn在Ubuntu上部署Flask Web應用

你好!歡迎閱讀個人博文,你能夠跳轉到個人我的博客網站,會有更好的排版效果和功能。
此外,本篇博文爲本人Pushy原創,如需轉載請註明出處:https://pushy.site/posts/1519817202html

我在不少的博客中都看過有關Flask應用的部署,也有不少博主在開博後都記錄了部署的教程,由於其中的坑能夠說很多。一開始我在網上看到相比較與UbuntuCentOS由於更新少做爲服務器的操做系統會更加穩定。因此在第一次購買雲服務器時,我選擇了CentOS,後來因爲CentOS不一樣發行版的Nginx緣故,我又換成了Ubuntu的鏡像前端

首先呢,咱們先來了解下關於Web服務器與Web應用還有WSGI之間的聯繫python

1、介紹

WSGI(Web Server Gateway Interface),翻譯爲Python web服務器網關接口,即PythonWeb應用程序(如Flask)和Web服務器(如Nginx)之間的一種通訊協議。也就是說,若是讓你的Web應用在任何服務器上運行,就必須遵循這個協議。nginx

那麼實現WSGI協議的web服務器有哪些呢?就好比uWSGIgunicorn。二者均可以做爲Web服務器。可能你在許多地方看到的都是採用Nginx + uWSGI(或gunicorn)的部署方式。實際上,直接經過uWSGIgunicorn直接部署也是可讓外網訪問的,那你可能會說,那要Nginx何用?別急,那麼接來下介紹另外一個Web服務器——Nginxgit

Nginx做爲一個高性能Web服務器,具備負載均衡、攔截靜態請求、高併發...等等許多功能,你可能要問了,這些功能和使用Nginx + WSGI容器的部署方式有什麼關係?github

首先是負載均衡,若是你瞭解過OSI模型的話,其實負載均衡器就是該模型中4~7層交換機中的一種,它的做用是可以僅經過一個前端惟一的URL訪問分發到後臺的多個服務器,這對於併發量很是大的企業級Web站點很是有效。在實際應用中咱們一般會讓Nginx監聽(綁定)80端口,經過多域名或者多個location分發到不一樣的後端應用。web

其次是攔截靜態請求,簡單來講,Nginx會攔截到靜態請求(靜態文件,如圖片),並交給本身處理。而動態請求內容將會經過WSGI容器交給Web應用處理;flask

Nginx還有其餘不少的功能,這裏便不一一介紹。那麼前面說了,直接經過uWSGIgunicorn也可讓外網訪問到的,可是鑑於Nginx具備高性能、高併發、靜態文件緩存、及以上兩點、甚至還能夠作到限流與訪問控制,因此選擇Nginx是頗有必要的;後端

這裏能夠說明,若是你選擇的架構是:Nginx + WSGI容器 + web應用,WSGI容器至關於一箇中間件;若是選擇的架構是uWSGI + web應用,WSGI容器則爲一個web服務器瀏覽器

2、實際部署:

該篇部署的教程是在你已經購買好虛擬主機,而且已經搭建好開發環境的前提下進行的,若是你尚未搭建好開發環境,能夠參考我寫的文檔:

阿里雲Ubuntu雲服務器上搭建Python和Flask的開發環境

廣泛的部署方式都是經過讓Nginx綁定80端口,並接受客戶端的請求將動態內容的請求反向代理給運行在本地端口的uWSGI或者Gunicorn,因此既能夠經過Nginx + uWSGI也能夠經過Nginx + Gunicorn來部署Flask應用,這篇教程中都將一一介紹這兩種方法

固然採用不一樣的WSGI容器,Nginx中的配置也會有所不一樣

1. Nginx + uWSGI:

1.1 配置uWSGI:

咱們如今虛擬環境下安裝好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交互的。

1.2 配置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;
        }
}

2. Nginx + Gunicorn

2.1 配置Gunicorn:

首先先在虛擬環境下安裝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

2.2 配置Nginx:

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

3、守護進程

若是你採起如上的任意一種部署方式,在Nginx與uWSGI或Gunicorn同時運行,而且配置無誤的狀態下,那麼你如今應該是能夠經過你的公網ip或者域名訪問到你的網站了。

可是還有一個問題,到目前爲止,uWSGI和gunicorn都是直接經過命令行運行,並不可以在後臺運行,也是當咱們關閉了xShell(或者你使用的是Putty及其餘SSH鏈接的軟件),將沒法再訪問到你的應用。因此咱們須要讓uWSGI或gunicorn在後臺運行,也就是所謂的daemon(守護進程)。

1. nohup:

若是你熟悉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應用了!

2. supervisor

可是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

參考資料:

Linux後臺進程管理利器:supervisor

相關文章
相關標籤/搜索