使用 Eventlet 和 Docker 部署 Flask-SocketIO 应用

问题描述 投票:0回答:0

我有一个简单的 flask 应用程序,它演示了如何使用客户端的网络摄像头流式传输网络摄像头视频。当我在本地运行应用程序时,一切运行良好,但是当我尝试在 render.com 和 gunicorn(用于生产)上使用 docker 部署应用程序时,我收到以下错误:

flask-client-camera  | 
flask-client-camera  | Error: class uri 'eventlet' invalid or not found: 
flask-client-camera  | 
flask-client-camera  | [Traceback (most recent call last):
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/gunicorn/util.py", line 124, in load_class
flask-client-camera  |     return pkg_resources.load_entry_point("gunicorn",
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/pkg_resources/__init__.py", line 534, in load_entry_point
flask-client-camera  |     return get_distribution(dist).load_entry_point(group, name)
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2930, in load_entry_point
flask-client-camera  |     return ep.load()
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2517, in load
flask-client-camera  |     return self.resolve()
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2523, in resolve
flask-client-camera  |     module = __import__(self.module_name, fromlist=['__name__'], level=0)
flask-client-camera  |   File "/usr/local/lib/python3.8/site-packages/gunicorn/workers/geventlet.py", line 18
flask-client-camera  |     from gunicorn.workers.async import AsyncWorker
flask-client-camera  |                           ^
flask-client-camera  | SyntaxError: invalid syntax
flask-client-camera  | ]

这是我的 Dockerfile:

FROM python:3.8.13-slim-bullseye

WORKDIR /app

RUN apt-get -y update && apt-get install -y \
  wget \
  ffmpeg \ 
  libsm6 \
  libxext6

RUN pip install --upgrade setuptools 

COPY requirements.txt .

RUN pip install -r requirements.txt

ADD . . 

CMD gunicorn --worker-class eventlet -w 1 app:app

Flask app.py 文件:

import base64
import os

import cv2
import numpy as np
from flask import Flask, render_template, send_from_directory
from flask_socketio import SocketIO, emit

app = Flask(__name__, static_folder="./templates/static")
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app)


@app.route("/favicon.ico")
def favicon():
    """
    The favicon function serves the favicon.ico file from the static directory.
    
    :return: A favicon
    """
    return send_from_directory(
        os.path.join(app.root_path, "static"),
        "favicon.ico",
        mimetype="image/vnd.microsoft.icon",
    )


def base64_to_image(base64_string):
    """
    The base64_to_image function accepts a base64 encoded string and returns an image.
    The function extracts the base64 binary data from the input string, decodes it, converts 
    the bytes to numpy array, and then decodes the numpy array as an image using OpenCV.
    
    :param base64_string: Pass the base64 encoded image string to the function
    :return: An image
    """
    base64_data = base64_string.split(",")[1]
    image_bytes = base64.b64decode(base64_data)
    image_array = np.frombuffer(image_bytes, dtype=np.uint8)
    image = cv2.imdecode(image_array, cv2.IMREAD_COLOR)
    return image


@socketio.on("connect")
def test_connect():
    """
    The test_connect function is used to test the connection between the client and server.
    It sends a message to the client letting it know that it has successfully connected.
    
    :return: A 'connected' string
    """
    print("Connected")
    emit("my response", {"data": "Connected"})


@socketio.on("image")
def receive_image(image):
    """
    The receive_image function takes in an image from the webcam, converts it to grayscale, and then emits
    the processed image back to the client.


    :param image: Pass the image data to the receive_image function
    :return: The image that was received from the client
    """
    # Decode the base64-encoded image data
    image = base64_to_image(image)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    frame_resized = cv2.resize(gray, (640, 360))
    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
    result, frame_encoded = cv2.imencode(".jpg", frame_resized, encode_param)
    processed_img_data = base64.b64encode(frame_encoded).decode()
    b64_src = "data:image/jpg;base64,"
    processed_img_data = b64_src + processed_img_data
    emit("processed_image", processed_img_data)


@app.route("/")
def index():
    """
    The index function returns the index.html template, which is a landing page for users.
    
    :return: The index
    """
    return render_template("index.html")


if __name__ == "__main__":
    socketio.run(app, port=os.getenv("PORT", default=5000), debug=os.getenv("DEBUG", default=True), host='0.0.0.0')

文件夹结构:

├── app.py
├── Dockerfile
├── LICENSE.md
├── README.md
├── render.yaml
├── requirements.txt
└── templates
    ├── index.html
    └── static
        ├── favicon.ico
        └── script.js

requirements.txt:

Flask-SocketIO==4.3.1
python-engineio==3.13.2
python-socketio==4.6.0
Flask==2.0.3
Werkzeug==2.0.3
opencv_python==4.7.0.68
numpy==1.24.2
gunicorn==18.0
eventlet==0.33.3

项目可以在Github上找到:https://github.com/Nneji123/flask-client-camera

python docker gunicorn flask-socketio eventlet
© www.soinside.com 2019 - 2024. All rights reserved.