Nginx+Gunicorn+Supervisor部署Flask應用

Flask 內置了簡單的 Web 環(huán)境,讓我們在開發(fā)的時候只需要專注于應用實現,而真正要在生產環(huán)境運行時這個簡單的 Web 環(huán)境就不夠用了,還需要一系列操作才能讓 Web 應用高效的運行起來?,F在記錄一下在生產環(huán)境部署 Flask 應用的其中一套方案:Nginx + Gunicorn + Supervisor。

1. 準備

1.1 項目結構

我的項目結構類似這樣, myapp 包是應用的主要代碼,其中的初始化文件 init 提供了創(chuàng)建程序實例的工廠方法 create_app ,主目錄下的 .flaskenv 和 .env 文件存儲了一些 Flask 程序要用到的環(huán)境變量。

MyApp
|----myapp
|    | __init__.py
|    | ...
| .flaskenv
| .env
| ...

當然一個最簡單的 Flask 應用可能類似下面這種結構也是可以的,我們只需要清楚自己最后的程序實例 app 的位置即可。

MyApp
| app.py
| ...

1.2 修改生產環(huán)境配置

這個配置寫在 .flaskenv 文件里面比較方便,后面運行時從里面讀取加載。

FLASK_ENV = production

1.3 在項目根目錄創(chuàng)建 wsgi.py

創(chuàng)建這個文件的作用主要有兩個:

  • 自行讀取文件中定義的環(huán)境變量,因為后面用正式服務器運行時不會自動從文件中加載。
  • 導入程序實例,方便啟動。
import os
from dotenv import load_dotenv

from myapp import create_app


# 讀取環(huán)境變量
flaskenv_path = os.path.join(os.path.dirname(__file__), '.flaskenv')
env_path = os.path.join(os.path.dirname(__file__), '.env')
if os.path.exists(flaskenv_path):
    load_dotenv(flaskenv_path)
if os.path.exists(env_path):
    load_dotenv(env_path)

# 如果是簡單的單文件結構,這里直接 from app import app 也可
app = create_app()

2. 使用Gunicorn啟動Flask應用

開發(fā)環(huán)境下使用flask run 命令或者程序中使用 app.run() 啟動的是由 Werkzeug 提供的 WSGI 服務器,它的性能很弱,我們需要一個更健壯的WSGI服務器,也叫WSGI容器,主流選擇是 uWSGIGunicorn ,也有其他像 Gevent,Waitress 等等,這里我們使用 Gunicorn,主要是簡單易用且高效。

2.1 安裝

Gunicorn 使用 pip 安裝即可,若有用虛擬環(huán)境,在虛擬環(huán)境中安裝。

pip install gunicorn

2.2 啟動

Gunicorn 啟動 Flask 程序需要指定包含程序實例的模塊,還有其他參數設置例如工作進程數,一般為cpu核心數,監(jiān)聽地址,設置為 0.0.0.0:端口號 即可監(jiān)聽外網,這里我們只需監(jiān)聽本地地址,因為后面會用到 Web服務器 監(jiān)聽外網然后轉發(fā)請求到本地地址。

# -w 6 工作線程數,相當于 --workers=6
# -b 127.0.0.1:8000 監(jiān)聽地址,相當于 --bind=127.0.0.1:8000
gunicorn -w 6 -b 127.0.0.1:8000 wsgi:app

3. 使用Supervisor管理進程

直接通過命令運行 Gunicorn 并不可靠,我們需要一個工具來自動在后臺運行它并同時監(jiān)控運行狀態(tài),自動重啟等。

3.1 安裝

sudo apt install supervisor

3.2 配置

全局配置文件在 /etc/supervisor/supervisord.conf,在同級 conf.d/ 目錄下創(chuàng)建自己的程序配置myapp.conf,注意目錄改成自己的目錄,command 要使用正確的虛擬環(huán)境(如果有):

[program:myapp]
directory=/home/assassin/tmp/MyApp
stdout_logfile=/home/assassin/tmp/MyApp/supervisor.log
stderr_logfile=/home/assassin/tmp/MyApp/supervisor.log
command=/home/assassin/usr/miniconda3/envs/flask/bin/gunicorn -w 6 -b 127.0.0.1:8000 wsgi:app
user=assassin
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true

3.3 啟動

重啟 supervisor 服務來加載配置好的 WSGI 程序。

sudo service supervisor restart

查看程序運行狀態(tài):

sudo supervisorctl status

停止/啟動程序:

sudo supervisorctl stop/start myapp

4. 使用Nginx提供反向代理

Gunicorn 這類WSGI服務器雖然內置了 Web 服務器,已經可以與客戶端交換數據,但是不夠健壯,更流行的方式是使用一個常規(guī)的 Web 服務器運行在前段為 WSGI 服務器提供反向代理,如Nginx,Apache等,這樣做的好處有:

  • 提高處理靜態(tài)文件的效率。Nginx可以對靜態(tài)文件設置緩存,速度非常快。
  • 提高安全系數。避免直接暴露 WSGI 服務器。
  • 提高處理能力。緩沖請求,預處理,負載均衡等。

這樣使用反向代理服務后,WSGI服務器只需要監(jiān)聽本地端口,由代理服務器監(jiān)聽外部端口,將請求轉發(fā)到WSGI服務器。

4.1 安裝

sudo apt install nginx

4.2 配置

新建 /etc/nginx/conf.d/myapp.conf 來配置代理服務

server {
        listen  15535;  # 監(jiān)聽15535端口來自外部的請求
        server_name  _;  # 如果映射了域名,可以代替_

        # 為HTTP規(guī)則 / 設置轉發(fā)
        location / {
            proxy_pass  http://127.0.0.1:8000;  # 轉發(fā)到本地端口
            proxy_redirect  off;

            # 重寫一些請求首部
            proxy_set_header  Host  $host;
            proxy_set_header  X-Real-IP  $remote_addr;
            proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Proto  $scheme;
        }

        # 為 /static 靜態(tài)資源請求設置轉發(fā),并指定緩存時間,這比從Flask中獲取快得多
        location /static {
            alias  /home/assassin/tmp/Bluelog/bluelog/static/;
            expires  10d;
        }
}

4.3 啟動

使用 sudo nginx -t 來測試配置文件的正確性,沒問題后便可以用 sudo service nginx restart 重啟Nginx服務。此時訪問主機地址的 15535 端口便可以訪問到 Flask 應用。

5. 補充

  • Nginx 和 supervisor 安裝后默認都是自啟動的,如果不需要,可以使用如下命令(Ubuntu):
# 查看服務狀態(tài)
service --status-all
# 查看自啟
systemctl list-unit-files | grep enable
# 關閉自啟
sudo systemctl disable nginx.service
sudo systemctl disable supervisor.service
# 打開自啟
sudo systemctl enable nginx.service
sudo systemctl enable supervisor.service
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容