Gunicorn: Docker 容器中的 Gunicorn + Flask + Tensorflow 不起作用

创建于 2019-10-03  ·  23评论  ·  资料来源: benoitc/gunicorn

你好

我有一个 TensorFlow 2.0 项目,它前面有一个很小的 ​​Flask API,所以我可以通过 HTTP 调用向模型发出请求,并且数据预处理已经在 API 中完成。 我选择 Gunicorn 在 docker 容器中运行我的 Flask/TensorFlow 应用程序。 可悲的是,Gunicorn 创建的工作进程挂在容器中,直到它被 Gunicorn 杀死。 服务器永远不会出现,我无法向它发出请求。 此外,相同的 Gunicorn 设置在 docker 之外,在我的主机中完美运行。

Docker 日志(它只是挂在那里并在很长时间后打印超时错误)

[2019-10-03 18:03:05 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-10-03 18:03:05 +0000] [1] [INFO] Listening at: http://127.0.0.1:8000 (1)
[2019-10-03 18:03:05 +0000] [1] [INFO] Using worker: sync
[2019-10-03 18:03:05 +0000] [8] [INFO] Booting worker with pid: 8
2019-10-03 18:03:08.126584: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-10-03 18:03:08.130017: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3392000000 Hz
2019-10-03 18:03:08.130306: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x55fbb23fb2d0 executing computations on platform Host. Devices:
2019-10-03 18:03:08.130365: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version

码头档案:

FROM python

RUN pip install gunicorn

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD [ "gunicorn", "--chdir", "src", "api:app" ]

api.py:

from flask import Flask, request
import inference

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def predict():
    if request.method == 'GET':
        return 'POST a json payload of {"imageBase64": "base64base64base64"} to this address to predict.'
    try:
        result = inference.run(request.json['imageBase64'])
        return result
    except Exception as e:
        return {'error': str(e)}, 500

if __name__ == "__main__":
    app.run()
else:
    print('\n * Server ready!')

推理.py

# Import packages
from __future__ import absolute_import, division, print_function, unicode_literals

import os
import tensorflow as tf
from tensorflow import keras
import PIL
import numpy as np
from io import BytesIO
import base64
import json

print("TensorFlow version is ", tf.__version__)

# Set variables
##########################################################################################
##########################################################################################

model_name = 'catsdogs'

base_dir = os.path.join(os.path.dirname(__file__), '..')
model_dir = os.path.join(base_dir, 'models')

##########################################################################################
##########################################################################################

# Load model
model = keras.models.load_model(os.path.join(model_dir, model_name + '.h5'))

# Load metadata
with open(os.path.join(model_dir, model_name + '_metadata.json')) as metadataFile:
    metadata = json.load(metadataFile)

# Split metadata
labels = metadata['training_labels']
image_size = metadata['image_size']

# Exported function for inference
def run(imgBase64):
    # Decode the base64 string
    image = PIL.Image.open(BytesIO(base64.b64decode(imgBase64)))

    # Pepare image
    image = image.resize((image_size, image_size), resample=PIL.Image.BILINEAR)
    image = image.convert("RGB")

    # Run prediction
    tensor = tf.cast(np.array(image), tf.float32) / 255.
    tensor = tf.expand_dims(tensor, 0, name=None)
    result = model.predict(tensor, steps=1)

    # Combine result with labels
    labeledResult = {}
    for i, label in enumerate(labels):
        labeledResult[label] = float(result[0][labels[label]])

    return labeledResult

我多年来一直在寻找解决方案,但一直没有想出任何办法,任何帮助将不胜感激。

谢谢!

Feedback Requested FeaturWorker FeaturIPC PlatforDocker

最有用的评论

有同样的问题。 据我可以从我自己的日志猜测,它看起来像tensorflow使用gevent ,你不能使用gevent在同一时间gunicorn . --workers--threads标志对我没有任何影响,但是从--worker-class=gevent更改--worker-class=gthread为我解决了这个问题。 谢谢@javabrett

所有23条评论

您的 Docker 设置是否限制了容器可用的最大内存?

经历一样。 不过,我不认为 Gunicorn 应该受到指责。 从容器中的 bash shell 运行python3 api.py时出现相同的错误。

@tlaanemaa你能确认@mackdelany所说的吗?

嘿。 很抱歉就这样消失了。

我的设置稍微限制了 Docker 的 RAM,但即使我取消了限制,也会发生同样的事情。

我将尝试在没有 gunicorn 的情况下运行 api 文件并返回报告。

谢谢!

@tlaanemaa 有什么消息吗?

@benoitc 嘿呀
对不起,我已经被其他东西带走了,没有时间更进一步。
我今天会试着戳这个然后回复你

所以我尝试在容器中没有 gunicorn 的情况下运行该应用程序,并且奏效了。
下面是我的 Dockerfile 的 CMD 位

作品:

CMD [ "python", "src/api.py" ]

日志:

2019-12-02 11:40:45.649503: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-12-02 11:40:45.653496: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2019-12-02 11:40:45.653999: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x55f969cf6a40 executing computations on platform Host. Devices:
2019-12-02 11:40:45.654045: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version
TensorFlow version is  2.0.0
 * Serving Flask app "api" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

不工作:

CMD [ "gunicorn", "--chdir", "src", "api:app" ]

日志:

[2019-12-02 11:39:22 +0000] [1] [INFO] Starting gunicorn 20.0.4
[2019-12-02 11:39:22 +0000] [1] [INFO] Listening at: http://127.0.0.1:8000 (1)
[2019-12-02 11:39:22 +0000] [1] [INFO] Using worker: sync
[2019-12-02 11:39:22 +0000] [9] [INFO] Booting worker with pid: 9
2019-12-02 11:39:24.041188: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-12-02 11:39:24.046495: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2019-12-02 11:39:24.047129: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5623e18b5200 executing computations on platform Host. Devices:
2019-12-02 11:39:24.047183: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version

此外,我已将存储库打开,以便您可以随意浏览。
可能会有所帮助

https://gitlab.com/tlaanemaa/image-classifier

Listening at: http://127.0.0.1:8000 (1)

问题可能是 gunicorn 正在侦听容器内的本地主机,因此无法从外部访问它?

我不这么认为,因为烧瓶应用程序正在做同样的事情并且正在工作。
此外,gunicorn 版本没有记录 tensorflow 版本,这表明问题发生在代码中的日志行之前。 在没有 gunicorn 的情况下运行时,只需烧瓶,然后它就会记录下来。
TensorFlow version is 2.0.0

它在调试级别说什么?

@tlaanemaa你的 Docker 守护进程网络是如何配置的? 根据@CaselIT 的评论,您的客户端似乎无法通过 Docker 网络访问 Gunicorn 端口。

您可以尝试使用 arg -b 0.0.0.0:8000启动 Gunicorn 吗?

我不认为问题出在网络上,因为至少从日志来看,服务器似乎根本没有启动,因为它从未命中 tensorflow 导入后的日志行

尽管如此,我尝试了你的建议,但它给了我一个错误

CMD [ "gunicorn", "-b", "0.0.0.0:8000", "--chdir", "src", "api:app" ]

_日志_

usage: gunicorn [OPTIONS] [APP_MODULE]
gunicorn: error: unrecognized arguments: -d

如果你想自己尝试,那么容器镜像可以在registry.gitlab.com/tlaanemaa/image-classifier 获得

@tlaanemaa你能重新发布你更新的Dockerfile 、镜像构建命令和容器运行命令吗?

@javabrett当然

  • Dockerfile: https ://gitlab.com/tlaanemaa/image-classifier/blob/master/Dockerfile
  • 构建命令: docker build -t tlaanemaa/image-classifier .
  • Container 是通过 Portainer 运行的,可悲的是,我不确定它使用哪个命令来执行此操作。 在那里没有做任何疯狂的事情,标准的东西,端口 8000 被转发。

_发布时的Dockerfile:_

FROM python:3.7

RUN pip install gunicorn

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD [ "gunicorn", "-b", "0.0.0.0:8000", "--chdir", "src", "api:app" ]

docker的完整日志是什么,你能粘贴它最终使用的命令行吗?

除非它正在做一些在这个问题的调试过程中不能放弃的事情,你现在可以在没有 Portainer 的情况下运行它吗?

这对我有用,Docker Desktop for Mac 2.1.0.5:

docker build -t tlaanemaa/image-classifier .
docker run -it --rm -p 8000:8000 tlaanemaa/image-classifier

接受POST请求。

请运行并发布完整的输出和结果。

我试过了,现在可以用了。
可能是-b标志修复了它吗?

非常感谢!

现在有趣的是,当我做 POST 请求时,thpose 很快,但 GET 请求非常慢。 经过一段时间的 GET 请求,这些请求变得很快,但是 POST 变得非常慢并且工作器超时。 一旦它响应该 POST,POST 又会很快,而 GET 会很慢。 似乎它可以快速完成一个并且它需要时间来切换:D

这些是 GET 很快而 POST 很慢时的日志,因为工作人员超时:

[2020-01-10 09:34:46 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:72)
[2020-01-10 09:34:46 +0000] [72] [INFO] Worker exiting (pid: 72)
[2020-01-10 09:34:47 +0000] [131] [INFO] Booting worker with pid: 131
TensorFlow version is  2.0.0
2020-01-10 09:34:48.946351: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2020-01-10 09:34:48.951124: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2208000000 Hz
2020-01-10 09:34:48.951612: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x56481dbabd80 executing computations on platform Host. Devices:
2020-01-10 09:34:48.951665: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version

 * Server ready!

此外,在某些情况下, * Server ready!日志似乎没有出现在 docker 日志中。 这也可能是误导。 不确定是什么原因造成的

Docker 中的当前服务器将配置为单线程/同步线程,这对于忙/阻塞来说是微不足道的,因此您很可能会看到这一点。 尝试添加一些参数,如--workers=2 --threads=4 --worker-class=gthread

谢谢@javabrett
那就修好了!

有同样的问题。 据我可以从我自己的日志猜测,它看起来像tensorflow使用gevent ,你不能使用gevent在同一时间gunicorn . --workers--threads标志对我没有任何影响,但是从--worker-class=gevent更改--worker-class=gthread为我解决了这个问题。 谢谢@javabrett

你好! 作为 gevent 的维护者和这个项目的贡献者,我可以明确地说 gevent 和 gunicorn 可以很好地协同工作。 各种库可能会干扰,但这不是 gunicorn 或 gevent 的错。 如果您不是这种情况,请打开一个新问题。 谢谢!

此页面是否有帮助?
0 / 5 - 0 等级