簡體   English   中英

為什么使用 gunicorn 和 uwsgi 運行 flask app.run 會出現問題?

[英]Why running flask app.run with gunicorn and uwsgi is problematic?

有一個想法表明不要在生產中使用 gunicorn 或 uwsgi 運行 flask 應用程序。 Tiangolo 在他的一個存儲庫中提到 app.run 應該僅用於開發,而不是部署或生產。 鏈接到 Tiangolo 對該主題的評論他的代碼如下:

from flask import Flask

app = Flask(__name__)

from .core import app_setup


if __name__ == "__main__":
    # Only for debugging while developing
    app.run(host="0.0.0.0", debug=True, port=80)

我的問題是為什么運行 flask 應用程序可能會出現問題(上述代碼的最后一行),應該刪除或注釋掉。 我進行了一系列測試,發現在生產環境中運行 flask 應用程序時,生成的進程數是相同的。 這是我用 gunicorn 進行的測試的輸出。

這是我的 docker-compose。 在第 12 行,您可以查看我是如何運行 gunicorn 的。

version: "3.7"
services:
  face:
    build: ./app
    container_name: face
    restart: always
    expose:
      - 660
    environment:
      - ENDPOINT=/face
      - FACE_DETECTION_MODEL=MTCNNTorchFaceDetector
    command: gunicorn --workers=2 --threads 1 -b 0.0.0.0:660 entry_point:app --worker-class sync

  nginx:
    build: ./nginx
    container_name: nginx
    restart: always
    ports:
      - 8000:80
    depends_on:
      - face

flask gunicorn 2 進程與 app.run:

root@e6c7d9ef03cc:/app# cat entry_point.py 
from endpoints import FaceDetection
from base_app import app, api, ENDPOINT

api.add_resource(FaceDetection, ENDPOINT)

if __name__ == '__main__':
    app.run("127.0.0.1", port=3000)
root@e6c7d9ef03cc:/app# lsof -i
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gunicorn   1 root    5u  IPv4 471109      0t0  TCP *:660 (LISTEN)
gunicorn   7 root    5u  IPv4 471109      0t0  TCP *:660 (LISTEN)
gunicorn   8 root    5u  IPv4 471109      0t0  TCP *:660 (LISTEN)
root@e6c7d9ef03cc:/app#

正如您在代碼中看到的,有 3 個處理器,其中一個是主處理器,另外兩個是工作處理器。

flask gunicorn 2 沒有 app.run 的進程(已注釋掉):

root@e6c7d9ef03cc:/app# cat entry_point.py 
from endpoints import FaceDetection
from base_app import app, api, ENDPOINT

api.add_resource(FaceDetection, ENDPOINT)

# if __name__ == '__main__':
#     app.run("127.0.0.1", port=3000)
root@e6c7d9ef03cc:/app# lsof -i
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gunicorn   1 root    5u  IPv4 466580      0t0  TCP *:660 (LISTEN)
gunicorn   8 root    5u  IPv4 466580      0t0  TCP *:660 (LISTEN)
gunicorn   9 root    5u  IPv4 466580      0t0  TCP *:660 (LISTEN)
root@e6c7d9ef03cc:/app#

輸出是相同的,並且丟棄主處理器,只有 2 個主要工作人員啟動並運行。
具有 4 個處理器的 gunicorn 應用程序也是如此。
使用 app.run:

root@f1d9f2d3a5d0:/app# cat entry_point.py 
from endpoints import FaceDetection
from base_app import app, api, ENDPOINT

api.add_resource(FaceDetection, ENDPOINT)

if __name__ == '__main__':
    app.run("127.0.0.1", port=3000)
root@f1d9f2d3a5d0:/app# lsof -i
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gunicorn   1 root    5u  IPv4 484435      0t0  TCP *:660 (LISTEN)
gunicorn   7 root    5u  IPv4 484435      0t0  TCP *:660 (LISTEN)
gunicorn   8 root    5u  IPv4 484435      0t0  TCP *:660 (LISTEN)
gunicorn   9 root    5u  IPv4 484435      0t0  TCP *:660 (LISTEN)
gunicorn  10 root    5u  IPv4 484435      0t0  TCP *:660 (LISTEN)
root@f1d9f2d3a5d0:/app#

沒有 app.run:

root@f1d9f2d3a5d0:/app# cat entry_point.py 
from endpoints import FaceDetection
from base_app import app, api, ENDPOINT

api.add_resource(FaceDetection, ENDPOINT)

# if __name__ == '__main__':
#     app.run("127.0.0.1", port=3000)
root@f1d9f2d3a5d0:/app# lsof -i
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gunicorn   1 root    5u  IPv4 476011      0t0  TCP *:660 (LISTEN)
gunicorn   8 root    5u  IPv4 476011      0t0  TCP *:660 (LISTEN)
gunicorn   9 root    5u  IPv4 476011      0t0  TCP *:660 (LISTEN)
gunicorn  10 root    5u  IPv4 476011      0t0  TCP *:660 (LISTEN)
gunicorn  11 root    5u  IPv4 476011      0t0  TCP *:660 (LISTEN)
root@f1d9f2d3a5d0:/app#

要重現問題,請克隆face-detection-flask-gunicron-docker-compose並運行以下命令:

# get the project
git clone https://github.com/pooya-mohammadi/face-detection-flask-nginx-gunicorn-docker.git
# cd to project's root 
cd ace-detection-flask-nginx-gunicorn-docker
# build the images and run the project
sudo docker-compose up --build
# open a new terminal
sudo docker ps -a 
# get the container-id for face-detection_face
# open a bash command with that container-id
sudo docker exec -it <container-i> bash # This opens a new command line
# install lsof to view listening services
apt-get install lsof
# view app.run condition
cat entry_point.py | grep app.run # The default is not commented. 
lsof -i  

在 entry_point.py 中注釋 app.run 並再次運行該過程。
要更改工作人員的數量,請修改 docker-compose.yml 中的第 12 行。

在研究了 gunicorn 庫一段時間后,我注意到 gunicorn 使用import.import_module來導入入口點模塊(包含應用程序的模塊,在我的例子中是 entry_point.py)和if __name__ == '__main__':不會被執行,放任何東西都很安全。 鏈接到 gunicorn 庫中的 import_app 方法 此方法是從方法load_wsgiapp 鏈接到主要運行器 class WSGIApplication 鏈接到 WSGIApplication class內的 load_wsgiapp 調用的。
正如我所注意到的,Tiangolo 意味着直接使用 flask 應用程序進行生產是不安全的,因為:

flask 應用服務器未針對生產性能或安全性進行開發或測試。

Justin Triplett 的回答(不和諧)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM