Docker + Nginx + Gunicorn + Flask + MySQL 502 Ошибка шлюза - PullRequest
0 голосов
/ 27 апреля 2020

Я разрабатываю свое веб-приложение, используя Docker + Nginx + Gunicorn + Flask + MySQL, и успешно настроил мое приложение для ответа на HTTP-запросы с помощью простой строки. Однако, когда я пытаюсь сделать вызов MySQL (через экземпляр класса Python, см. Пример ниже), мое приложение возвращает ошибку 502 неверного шлюза. Есть некоторые полезные руководства по этому типу проблемы (https://www.datadoghq.com/blog/nginx-502-bad-gateway-errors-gunicorn/#gunicorn -isnt-running ), и переполнение стека изобилует похожими примерами, но, похоже, ничто не решает мою конкретную проблему c.

Я пришел к выводу, что это вызвано проблемами с сервером WSGI, когда задействована функция MySQL: после проб и ошибок, когда я запускаю Flask приложение напрямую (используя атрибут «cmd» в моем файле docker -compose.yml), вся система работает должным образом - хотя это не рекомендуется, поскольку мои журналы полны предупреждений Flask о том, что его следует запускать через сервер WSGI. Однако это позволило мне проверить, что MySQL все работает нормально. Однако, когда я запускаю приложение Flask через сервер WSGI (Gunicorn, снова используя команду «cmd» в моем файле docker -compose.yml), приложение возвращает 502 ошибки, когда я пытаюсь попасть в конечную точку, которая вызывает MySQL function.

Я проверил с библиотеками uWSGI и Gunicorn (в настоящее время я использую Gunicorn), и проблема точно такая же - отвечать строками верните нормально, все, что связано с использованием команды MySQL, возвращает ошибку 502.

Вот мои настройки Gunicorn (заданные в качестве переменной среды в контейнере Docker с использованием смонтированного файла .env): GUNICORN_CMD_ARGS=--bind=0.0.0.0:8000 --workers=1 --threads=1 --max-requests=0 --keep-alive=5 --log-level debug

Я получаю эти ошибки, зарегистрированные в Docker:

-nginx container name-  | -timestamp- [error] 7#7: *20 upstream prematurely closed connection while reading response header from upstream, client: 172.21.0.1, server: localhost, request: "GET /folder/page HTTP/1.1", upstream: "http://172.21.0.3:8000/folder/page", host: "localhost:5000"
-app container name-   | -timestamp- [14] [INFO] Booting worker with pid: 14

Вот мое Flask приложение. Как только я закомментирую переменную 'tests', все работает (хотя она возвращает только регистрацию автомобиля):

import logging,sys
from flask import Flask,render_template,request
from classes import Vehicle

app = Flask(__name__)

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

@app.route("/")
def index():
    print(request.headers)
    user = {'username' : 'Mario'}
    posts = [
        {
            'author': {'username': 'John'},
            'body': 'Beautiful day in Portland!'
        },
        {
            'author': {'username': 'Susan'},
            'body': 'Beautiful day in Seattle!'
        }
    ]
    return render_template('index.html',title='Home',user=user,posts=posts)

@app.route("/reg/<reg_no>")
def regroute(reg_no):
    car = Vehicle(reg_no)
    tests = car.MethodThatCallsMySQL()
    return f"<html><head></head><body>{car.registration}<br>{car}</body></html>"

Вот мой класс Vehicle. Я удалил запрос, но он был протестирован для работы в моем объяснении выше.

import os,mysql.connector,logging,sys
from mysql.connector.errors import Error

logger = logging.getLogger('dev')
logger.setLevel(logging.DEBUG)


class Vehicle(object):
    def __init__(self,registration):
        self.host = os.environ['HOST']
        self.user = os.environ['USER']
        self.pw = os.environ['PASSWORD']
        self.database = os.environ['DATABASE']
        self.registration = registration

    def MethodThatCallsMySQL(self):
        try:
            db = mysql.connector.connect(host=self.host,user=self.user,password=self.pw,database=self.database)
            query = --query that has been tested to work—-
            cur = db.cursor(dictionary=True)
            cur.execute(query,(self.registration,))
            results = cur.fetchall()
            cur.close()
            return results
        except Error as e:
            logger.error(e)
        except UnboundLocalError as ule:
            logger.error(ule)
        except Exception as ex:
            logger.error(ex)
        finally:
            db.close()

Файл WSGI, который я запускаю, относительно прост. Я также попытался добавить аргумент debug=True к app.run(), и у меня возникла та же проблема:

from routes import app

if __name__ == "__main__":
    app.run()

Наконец, вот мой файл docker -compose.yml:

version: "3.7"
services:
  web-nginx:
    build: ./network
    image: containername/nginx
    volumes:
      - type: bind
        source: ./static
        target: /home/static
    ports:
      - "5000:5000"

  web-app:
    build: ./app
    image: containername/app
    env_file:
      - ./credentials/app-variables.env
      - ./app/gunicorn.env
    command: gunicorn wsgi:app

    #I have tested running the Flask application directly by calling the wsgi program (the program then responds with the current information from DB. This is how I did it:
    #command: python wsgi.py

  dwh:
    image: mysql:8
    volumes:
      - type: bind
        source: ./extractor/db/setup
        target: /docker-entrypoint-initdb.d
    env_file:
      - ./credentials/db-variables.env

Поиск похожих проблем в StackOverflow предполагает проблему с памятью, но моя статистика Docker предполагает очень низкое использование памяти. Я застрял и ищу совета.

Спасибо

...