如何在Docker容器中将Flask应用程序调试模式设置为True

时间:2019-05-03 08:45:48

标签: docker flask

我正在Docker容器中运行Flask应用程序,但是调试时遇到问题。在我的容器中,我有三个微服务。

docker-compose.yml

version: '2.1'
services:
  files:
    image: busybox
    volumes:
     [..]

  grafana:
     [..]

  prometheus:
     [..]

  aggregatore:
   [..] 

  classificatore:
    build: classificatore/.
    volumes:    
      - [..]
    volumes_from: 
      - files
    ports: 
      - [..]
    command: ["python", "/src/main.py"]
    depends_on: 
      rabbit:
        condition: service_healthy

  testmicro:
    [..]    
  rabbit:
    [..]

classificatore服务中,我按照以下步骤构建Docker:

classificatore / Dockerfile

FROM python:3
RUN mkdir /src
ADD requirements.txt /src/.
WORKDIR /src
RUN pip install -r requirements.txt
ADD . /src/.
RUN mkdir -p /tmp/reqdoc
CMD ["python", "main.py"]

classificatore/main.py文件中

from time import time
from sam import firstRead, secondRead, lastRead, createClassificationMatrix
from sam import splitClassificationMatrix, checkIfNeedSplit, printMatrix
from util import Rabbit, log, moveFile
from uuid import uuid4
from flask import Flask, request, render_template, redirect, send_from_directory
import os
import configparser
import json
from prometheus_client import start_http_server, Summary, Counter

config = configparser.ConfigParser()
config.read('config.ini')
rabbit = Rabbit()

inputDir = os.environ['INPUT_DIR'] if 'INPUT_DIR' in os.environ else config['DEFAULT']['INPUT_DIR']

# Create a metric to track time spent
REQUEST_TIME = Summary('classification_processing_seconds', 'Time spent to process a SAM file')
COUNTER_INPUT_FILE_SIZE = Counter('input_sam_size', 'Sum of input SAM file size')
COUNTER_OUTPUT_FILE_SIZE = Counter('output_sam_size', 'Sum of output SAM file size')
start_http_server(8000)

@REQUEST_TIME.time()
def classification(baseNameFile, AU_SIZE):
    nameFile = inputDir + "/" + baseNameFile
    startTime = time()

    numeroLetture = 1
    file_id = str(uuid4())
    log.info("Analizzo il file YYYYY (NomeFile: %s, Id: %s, AU_SIZE: %s)" % (nameFile, file_id, AU_SIZE))
    rnameArray, parameter_set = firstRead(nameFile)
    classificationMatrix = createClassificationMatrix(rnameArray)
    log.info("Creo un numero di range che dovrebbe dividire il file in file da %s reads" % (AU_SIZE))
    while (checkIfNeedSplit(classificationMatrix, AU_SIZE)):
        classificationMatrix = splitClassificationMatrix(classificationMatrix, AU_SIZE)
        log.info("Leggo il file di nuovo, perche' alcuni range sono troppo grandi")
        classificationMatrix = secondRead(nameFile, classificationMatrix)
        numeroLetture = numeroLetture + 1
    printMatrix(classificationMatrix)
    log.info("Sono state fatte %s letture" % (numeroLetture))
    log.info("Adesso scrivo i file")
    au_list = lastRead(nameFile, file_id, classificationMatrix, parameter_set['myRnameDict'])
    COUNTER_INPUT_FILE_SIZE.inc(os.path.getsize(nameFile))
    COUNTER_OUTPUT_FILE_SIZE.inc(moveFile(au_list, file_id))
    rabbit.enque_tasks(parameter_set, au_list, file_id)

    log.info("Tempo totale impiegato: %s sec" % int(time() - startTime))

app = Flask( __name__ , template_folder='./web')

@app.route("/")
def index(message=None):
    log.info("Sono PRin index!!!")
    samFiles = os.listdir(config['DEFAULT']['INPUT_DIR'])
    samFiles = list(filter(lambda x: x.endswith('.sam'), samFiles))
    samFiles.sort()
    mpeggFiles = os.listdir(config['DEFAULT']['MPEGG_DIR'])
    mpeggFiles.sort()
    mpeggFiles = list(filter(lambda x: x.endswith('.mpegg'), mpeggFiles))
    return render_template('index.html', samFiles=samFiles, mpeggFiles=mpeggFiles, message=message)

@app.route("/upload", methods=['POST'])
def upload():
    f = request.files['file']
    f.save(os.path.join(config['DEFAULT']['INPUT_DIR'], f.filename))
    return index("Upload avvenuto con successo")

@app.route("/encode", methods=['POST'])
def encode():
    filename = request.form['filename']
    AU_SIZE = int(request.form['AU_SIZE'])
    classification(filename, AU_SIZE)
    return index("Encoding iniziato correttamente per il file: %s" % (filename))

@app.route('/download/<filename>', methods=['GET', 'POST'])
def download(filename):
    log.info ("Download %s" % filename)
    mpeggDir = config['DEFAULT']['MPEGG_DIR']
    log.debug ("mpeggDir: %s" % mpeggDir)
    filepath = os.path.join(mpeggDir, filename)
    log.debug ("My filepath: %s" % filepath)
    return send_from_directory(directory=mpeggDir, filename=filename)



if __name__ == "__main__" :
    app.run( host = '0.0.0.0' , debug = False )

我通过运行以下程序构建应用程序:

$ docker-compose build
$ docker-compose up -d

要检查分类器中的日志,请执行以下操作:

docker logs <mycontainername>

如果在classificatore / main.py中

if __name__ == "__main__" :
    app.run( host = '0.0.0.0' , debug = False )

我明白了

 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
2019-05-03 08:38:25,406  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

如果在classificatore / main.py中,我将debug设置为True

if __name__ == "__main__" :
    app.run( host = '0.0.0.0' , debug = True )

我明白了

* Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
2019-05-03 08:40:57,857  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
2019-05-03 08:40:57,858  * Restarting with stat
Traceback (most recent call last):
  File "/src/main.py", line 22, in <module>
    start_http_server(8000)
  File "/usr/local/lib/python3.7/site-packages/prometheus_client/exposition.py", line 181, in start_http_server
    httpd = _ThreadingSimpleServer((addr, port), CustomMetricsHandler)
  File "/usr/local/lib/python3.7/socketserver.py", line 452, in __init__
    self.server_bind()
  File "/usr/local/lib/python3.7/http/server.py", line 137, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "/usr/local/lib/python3.7/socketserver.py", line 466, in server_bind
    self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use

我想我正在搞乱端口,但在Docker中我还是个新手。

非常欢迎任何帮助!

提前谢谢

编辑1:$docker ps -a

的输出
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS                      PORTS                                                   NAMES
bb7c9a5b80eb        encoder_mpeg-pre-encoder   "python main.py"         2 minutes ago       Up 12 seconds                                                                       encoder_mpeg-pre-encoder_1
6a523161c191        encoder_classificatore     "python /src/main.py"    2 minutes ago       Exited (1) 11 seconds ago                                                           encoder_classificatore_1
e5d0287e9129        encoder_aggregatore        "python /src/main.py"    5 minutes ago       Up 12 seconds               0.0.0.0:8000->8000/tcp                                  encoder_aggregatore_1
907327ef0342        grafana/grafana:5.1.0      "/run.sh"                6 minutes ago       Up 18 seconds               0.0.0.0:3000->3000/tcp                                  encoder_grafana_1
e57064e76aa1        busybox                    "sh"                     6 minutes ago       Exited (0) 18 seconds ago                                                           encoder_files_1
2b42907a31c4        rabbitmq                   "docker-entrypoint.s…"   6 minutes ago       Up 18 seconds (healthy)     4369/tcp, 5671/tcp, 25672/tcp, 0.0.0.0:5672->5672/tcp   encoder_rabbit_1
3f509108b69d        prom/prometheus            "/bin/prometheus --c…"   6 minutes ago       Up 18 seconds               0.0.0.0:9090->9090/tcp                                  encoder_prometheus_1

2 个答案:

答案 0 :(得分:0)

我想您正在docker内部更改文件。在理想的环境中,您需要在正在进行实际开发的主机上对其进行更改,然后构建并运行该组合。

在docker主机上更改classificatore/main.py文件-

if __name__ == "__main__" :
    app.run( host = '0.0.0.0' , debug = True )

再次构建并运行该应用-

$ docker-compose build
$ docker-compose up -d

在这种情况下,最好使用环境变量,这样您就不必每次都为调试开关更改源代码。

要从头开始再次构建撰写,请在以下命令中运行-

$ docker-compose down -v
$ docker-compose build --no-cache
$ docker-compose up -d 

如果仍然收到错误,请在运行上述命令后共享docker ps的输出。

我可以看到以下错误-

  File "/src/main.py", line 22, in <module>
    start_http_server(8000)

您的docker ps输出显示端口8000上已经在运行其他命令,可能是aggegatore。发布start_http_server(8000)也在尝试在同一网络上的端口8000上运行,这在这里引起了冲突。尝试以所需的方式更改端口,以免发生冲突。

答案 1 :(得分:0)

编辑1:

通过使用DEBUG=True,您告诉Flask每次main.py更改时都要重新加载服务器。这样,它每次都会调用main.py,杀死该应用程序,然后在此过程中在端口5000中重新启动它。这是预期的行为。

问题是您还调用了start_http_server(8000),该调用在端口8000中创建了一个服务器。 Flask无法处理此过程,导致异常,因为先前的实例已在使用该端口。

对此错误进行了追溯(OSError: [Errno 98] Address already in use),但提示是该错误发生在重启服务器之后。

2019-05-03 08:40:57,857  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
2019-05-03 08:40:57,858  * Restarting with stat
Traceback (most recent call last):
  File "/src/main.py", line 22, in <module>
    start_http_server(8000)
  File "/usr/local/lib/python3.7/site-packages/prometheus_client/exposition.py", line 181, in start_http_server
    httpd = _ThreadingSimpleServer((addr, port), CustomMetricsHandler)

您需要在main.py脚本之外处理该服务的生命周期,或处理异常。

编辑2:

您的问题与Docker无关,而更多地是关于在Flask应用程序中设置 prometheus 。请注意,prometheus_client/exposition.py是引发异常的那个。

有一些扩展程序可以帮助解决这个问题,例如:

也许this也为解决方案提供了一些启示,但是请注意,这不是您在这里要的

编辑3:

我建议先尝试一下这些扩展,这意味着重构您的代码。从那里开始,如果在实现扩展时遇到问题,则创建另一个问题,提供一个mcve