为什么 运行 flask app.run gunicorn 和 uwsgi 有问题?
Why running flask app.run with gunicorn and uwsgi is problematic?
有一个想法表明不要 运行 在生产中使用 gunicorn 或 uwsgi 的 flask 应用程序。 Tiangolo 在他的一个存储库中提到 app.run 应该只用于开发,而不是部署或生产。 Link to Tiangolo's comment on this topic
他的代码如下:
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)
我的问题是为什么 运行ning flask 应用程序可能有问题(上述代码的最后一行)并且应该被删除或注释掉。我进行了一系列测试,发现在生产中使用或使用 运行ning flask app 生成的进程数是相同的。这是我用 gunicorn 测试的输出。
这是我的 docker-撰写。在第 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 个处理器,其中一个是主处理器,另外两个是工作处理器。
没有app.run的flask gunicorn 2进程(已注释掉):
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 个主要工作进程启动和 运行ning。
具有 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)和代码under if __name__ == '__main__':
将不会被执行,将任何东西放在那里是非常安全的。 Link to import_app method in gunicorn library. This method is called from method load_wsgiapp
link to load_wsgiapp inside the primary runner class WSGIApplication
Link to WSGIApplication class.
正如我注意到 Tiangolo 意味着直接使用 flask 应用程序进行生产是不安全的,因为:
The flask application server is not developed or tested for production performance or security.
有一个想法表明不要 运行 在生产中使用 gunicorn 或 uwsgi 的 flask 应用程序。 Tiangolo 在他的一个存储库中提到 app.run 应该只用于开发,而不是部署或生产。 Link to Tiangolo's comment on this topic 他的代码如下:
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)
我的问题是为什么 运行ning flask 应用程序可能有问题(上述代码的最后一行)并且应该被删除或注释掉。我进行了一系列测试,发现在生产中使用或使用 运行ning flask app 生成的进程数是相同的。这是我用 gunicorn 测试的输出。
这是我的 docker-撰写。在第 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 个处理器,其中一个是主处理器,另外两个是工作处理器。
没有app.run的flask gunicorn 2进程(已注释掉):
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 个主要工作进程启动和 运行ning。
具有 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.
在研究 gunicorn 库一段时间后,我注意到 gunicorn 使用 import.import_module
导入入口点模块(包含应用程序的模块,在我的例子中是 entry_point.py)和代码under if __name__ == '__main__':
将不会被执行,将任何东西放在那里是非常安全的。 Link to import_app method in gunicorn library. This method is called from method load_wsgiapp
link to load_wsgiapp inside the primary runner class WSGIApplication
Link to WSGIApplication class.
正如我注意到 Tiangolo 意味着直接使用 flask 应用程序进行生产是不安全的,因为:
The flask application server is not developed or tested for production performance or security.