1. 程式人生 > >如何使用Nginx和uWSGI或Gunicorn在Ubuntu上部署Flask Web應用

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

習慣 ade 通信 文件名 bubuko 查看 ... 第一次 dem

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

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

一、介紹

WSGI(Web Server Gateway Interface),翻譯為Python web服務器網關接口,即PythonWeb應用程序(如Flask)和Web服務器(如Nginx

)之間的一種通信協議。也就是說,如果讓你的Web應用在任何服務器上運行,就必須遵循這個協議。

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

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

首先是負載均衡,如果你了解過OSI模型的話,其實負載均衡器就是該模型中4~7層交換機中的一種,它的作用是能夠僅通過一個前端唯一的URL訪問分發到後臺的多個服務器,這對於並發量非常大的企業級Web站點非常有效。在實際應用中我們通常會讓Nginx監聽(綁定)80端口,通過多域名或者多個location分發到不同的後端應用。

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

Nginx還有其他很多的功能,這裏便不一一介紹。那麽前面說了,直接通過uWSGIgunicorn也可以讓外網訪問到的,但是鑒於Nginx

具有高性能、高並發、靜態文件緩存、及以上兩點、甚至還可以做到限流與訪問控制,所以選擇Nginx是很有必要的;

這裏可以說明,如果你選擇的架構是:Nginx + WSGI容器 + web應用,WSGI容器相當於一個中間件;如果選擇的架構是uWSGI + web應用,WSGI容器則為一個web服務器

二、實際部署:

該篇部署的教程是在你已經購買好虛擬主機,並且已經搭建好開發環境的前提下進行的,如果你還沒有搭建好開發環境,可以參考我寫的文檔:

阿裏雲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

三、守護進程

如果你采取如上的任意一種部署方式,在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

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