如何使用Nginx, Gunicorn與Supervisor 部署一個Flask App

前言

前陣子,因為隔壁組的關係,需要建置聊天機器人在外網,所以需要在外面的雲端平台上建置機器人的服務,這樣一來外面的人才可以存取到機器人,因為後端預測語意分析是用Python寫成的,為了要整合起來的便利,所以需要使用Python來建置後端與機器人。

因為Messenger機器人是透過Web後端進行存取與溝通,所以本篇文章是在教學,如何使用Nginx, gunicorn與supervisor 進行搭配,來部署一個Flask App

分別先講一下這四個工具每個的工作:

  1. Flask: 後端程式,一個Python web framework
  2. Nginx: 反向代理
  3. Gunicorn: 幫助我們部署Flask App
  4. Supervisor: 監控與控制Gnuicron的程序(process)
  5. inotify-tools: 監控當後端的code改變時會自動的更新

前置需要先已經設定的東西

  • 已經有一台虛擬私人主機(VPS, Virtual Private Server)
  • Ubuntu 16.04
  • 已經有網域並指向到這台主機的IP位址
  • Python3 (不用安裝,Ubnutu已經內建)

第一步:登入主機

首先,先登入主機。


ssh username@domain_or_ip_address

第二步:安裝Nginx

接著,要安裝好Nginx。


sudo apt-get update

sudo apt-get install nginx

第三步:安裝所需要用的套件


sudo apt-get install supervisor python-pip3 python3-virtualenv

  • supervisor套件先前已經提過,這裡就不在贅述
  • python-pip3 是用於Python3 的pip3 套件管理系統
  • python-virtualenv是用於Python2/Python3的虛擬環境,可以幫我們把Python環境獨立出來與系統環境分開

第四步:建立一個虛擬環境

因為我們的Flask App為了不要與系統環境污染,因此需要建立一個虛擬環境來做這件事情。因此我們建立一個虛擬環境,而名字叫做simple-bot,因為建置環境時,預設會使用Python2做建置環境的對象,所以要在後面指定要建立的Python設定檔。


virtualenv simple-bot --python=/usr/bin/python3

接著建立好環境之後,切換到simple-bot的環境,其指令如下


source ../simplebot/bin/activate

如果是使用Fish shell的話,要執行下面的指令來切換環境


source ../simplebot/bin/activate.fish

如果要離開這個的環境,這時候只需要執行下面的指令即可:


deactivate

寫一個Hello Flask App

下面是一個基本的Hello Flask App


from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
return "Hello World"

if __name__ == '__main__':
app.run(debug=True)

接著執行下面的app.py


python3 app.py

接著使用瀏覽器去拜訪:http://127.0.0.1:5000,接著就會看到下面的畫面了。

安裝Gunicorn

根據英文說法,這個Python3 套件是叫做:


Gunicorn ‘Green Unicorn’ is a Python WSGI HTTP Server for UNIX.

意思就是,用來在UNIX相關作業系統上做Python WSGI HTTP Server

利用下面的方式把Gunicorn安裝起來


pip3 install gunicorn

安裝Supervisor

這是一個允許在UNIX相關作業系統下,可以監控與控制一些指定的程序(processes)

使用前,要先安裝好這個名稱的套件。


sudo apt-get install supervisor

接著在 /etc/supervisor/conf.d/ 目錄下面建立一個叫做HelloBot.conf的設定檔案


[program:HelloBot]
directory=/home/username/hellobot
command=/home/username/hellobot/bin/gunicorn app:app -b 127.0.0.1:8000 --reload --max-requests 1 --access-logfile=- --error-logfile=-
autostart=true
autorestart=true
stderr_logfile=/var/log/HelloBot.err.log
stdout_logfile=/var/log/HelloBot.out.log

這邊來解釋一下,上面每一行的意義。

  1. 第一行的[program:HelloBot]是定義HelloBot這個要監控的程序名稱
  2. 第二行是定義工作目錄(working directory)
  3. 第三行是定義指令,要執行與監控的這個process程序
    這裡除了執行app.py程式起來之外,還有定義跑起來的port number以及需要reload
    還有定義access log 與 error log 是要抓STDOUT與STDERR的輸出。
  4. 第四行與第五行則是定義開機會自動起動。
  5. 倒數兩行則是定義stderr log與stdout log要放在哪一個檔案路徑裡面。

gunicorn所帶的–reload –max-requests 1這兩個參數可以讓gunicorn將程式碼自動更新。

設定好相對應檔案之後,接著執行下面的指令讓supervisor可以讀到新的程序設定檔。

以及為了要載入這個新的程式,必須要重啟supervisor服務。


sudo supervisorctl reread
sudo service supervisor restart

設定Nginx反向代理(reversed proxy)

所謂的反向代理,意思就是在server端上設定當server端收到某一個請求位址之後,可以透過這台server將所有請求導向給另一個真正可以處理這些請求參數服務的後端服務。

所以依照這個定義,則可以將我們上述的兩個東西結合在一起,就會變成:

  • Nginx當作反向代理的server
  • Flask App則是真正處理請求得後端服務

這樣的好處就是,使用者不知道後面是Flask App在做處理,只知道有Nginx的server存在。

從上述的設定檔得知,Flask App服務是跑在127.0.0.1:8000上面,因此我們需要按照下面的方式設定好我們所需要的反向代理設定。

用vim編輯器打開:/etc/nginx/sites-available/default的設定檔

打開之後,找到server區塊,並把下面這一行加進去。

若location /的區塊裡有try_files $uri $uri/ =404;也請記得要刪除。


location / {
proxy_pass http://127.0.0.1:8000;

}

接著檢查設定語法是否正確並重新啟動Nginx服務


sudo nginx -t

sudo service nginx restart

安裝inotify

因為有時候會改一些code讓後端程式變得跟之前不一樣,但是supervisor與Gunicorn並不知道程式碼有更動,因此為了要讓Gunicorn知道程式碼已經變動,所以我們要inotify-tools來幫助我們完成這件事情。使用這個之前,需要在Ubuntu上安裝inotify-tools套件


sudo apt-get update

sudo apt-get install inotify-tools

接著每當同一支程式已經有更新的時候,記得執行下面的指令:

sudo service supervisor restart

這樣就可以把新的程式真正的更新上去了!

結論

上面我們一共安裝了這一些的Python3 套件:


Flask==0.12.2
uwsgi==2.0.17.1
gunicorn==19.9.0
inotify==0.2.10

我們可以定義一個requirements.txt並使用pip3安裝就可以把全部的Python3 套件都安裝好!

我們就可以用下面的方式安裝起來。


pip3 install -r requirements.txt

參考資料