如何在Docker上运行Gunicorn

51

当 Docker 启动时,我有2个互相依赖的文件。一个是 Flask 文件,另一个是包含几个函数的文件。当 Docker 启动时,只有函数文件会被执行,但它会从 Flask 文件中导入 Flask 变量。例如:

Flask 文件

import flask
from flask import Flask, request
import json

_flask = Flask(__name__)

@_flask.route('/', methods = ['POST'])
def flask_main():
    s = str(request.form['abc'])
    ind = global_fn_main(param1,param2,param3)
    return ind

def run(fn_main):
    global global_fn_main
    global_fn_main = fn_main
    _flask.run(debug = False, port = 8080, host = '0.0.0.0', threaded = True)

主文件

import flaskfile
#a few functions then
if__name__ == '__main__':
    flaskfile.run(main_fn)

脚本可以正常运行,无需使用gunicorn。

Dockerfile

  FROM python-flask
  ADD *.py *.pyc /code/
  ADD requirements.txt /code/
  WORKDIR /code
  EXPOSE 8080
  CMD ["python","main_file.py"]

在命令行中,通常我会这样做:docker run -it -p 8080:8080 my_image_name,然后docker会开始运行并监听。

现在要使用gunicorn: 我尝试修改dockerfile中的CMD参数为:

["gunicorn", "-w", "20", "-b", "127.0.0.1:8083", "main_file:flaskfile"]

但它只是不断退出。我没有正确编写Docker Gunicorn命令吗?


当容器退出时,您看到了什么错误? - aquil.abdullah
6个回答

81

本周我刚碰到了这个问题,在寻找答案的过程中偶然看到了你的问题。可以说你现在已经解决了这个问题或者采用了其他方法,但是为了将来的参考:

我的Dockerfile命令是:

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

第一个 "app" 是模块名,第二个 "app" 是 WSGI 可调用函数的名称,在您的情况下,它 应该 从您的代码中使用 _flask,尽管您还有其他一些不确定的事情。

Gunicorn 取代了代码中所有的运行语句,如果 Flask 的开发 Web 服务器和 Gunicorn 尝试使用相同的端口,则可能会导致冲突并使 Gunicorn 崩溃。

请注意,当由 Gunicorn 运行时,__name__ 不是 "main"。在我的示例中,它等于 "app"。

在我作为初学者的级别上,对于 Python、Docker 和 Gunicorn,最快的调试方法是注释掉 Dockerfile 中的 "CMD",让容器运行起来:

docker run -it -d -p 8080:8080 my_image_name

进入正在运行的容器:

 docker exec -it container_name /bin/bash

从命令行启动Gunicorn,直到它能够正常工作为止,然后使用curl进行测试-我在我的app.py文件中保留了一个基本路由,它只打印出"Hi"并且没有验证服务器是否已经绑定到主机端口之前在线。


8080端口还是8000端口? - burtsevyg
第二个示例仅用于快速调试,不会产生冲突 - 8000 是其正常运行的设置。 - user7504939
在CMD中,8080或-p任意端口:8000。 - burtsevyg
3
谢谢,这解决了我不能连接的问题。Gunicorn默认绑定到127.0.0.1,这是无法从外部访问的(例如通过Docker的端口转发)。 - Fax
@Fax,您的评论帮我澄清了问题。谢谢! - Jesse H.

26

在过去的三天中,我一直在解决这个问题。我发现你只需要绑定到不可路由的元地址 0.0.0.0 而不是回环IP 127.0.0.1:

CMD ["gunicorn" , "--bind", "0.0.0.0:8000", "app:app"]

并且别忘了暴露端口。其中一种方法是在 Dockerfile 中使用 EXPOSE:

EXPOSE 8000

现在:

docker build -t test .

最后,您可以运行:

docker run -d -p 8000:8000 test

5
0.0.0.0的意思是:绑定在所有可用接口上,包括本地主机,也称为“127.0.0.1”。 - kalou.net
感谢@kalou.net。请检查,现在已经修复。 - Mohamad Al Mdfaa

6
这是我的Dockerfile的最后一部分,其中包含Django应用程序。
EXPOSE 8002
COPY entrypoint.sh /code/
WORKDIR /code
ENTRYPOINT ["sh", "entrypoint.sh"]

然后在entrypoint.sh中。
#!/bin/bash

# Prepare log files and start outputting logs to stdout
mkdir -p /code/logs
touch /code/logs/gunicorn.log
touch /code/logs/gunicorn-access.log
tail -n 0 -f /code/logs/gunicorn*.log &

export DJANGO_SETTINGS_MODULE=django_docker_azure.settings

exec gunicorn django_docker_azure.wsgi:application \
    --name django_docker_azure \
    --bind 0.0.0.0:8002 \
    --workers 5 \
    --log-level=info \
    --log-file=/code/logs/gunicorn.log \
    --access-logfile=/code/logs/gunicorn-access.log \
"$@"

希望这对您有所帮助。


这段代码在我这边会是什么样子?exec gunicorn django_docker_azure.wsgi:application 我能使用 exec gunicorn my_docker_image.wsgi:application 吗? - jxn
这部分涉及Django应用程序,我之前只使用过Flask,所以无法给你任何提示。抱歉。 - e.arbitrio

3
我尝试运行一个Flask应用程序。我发现你可以只使用以下内容:
ENTRYPOINT['gunicorn', '-b', ':8080', 'app:APP']
这将获取您指定的文件并在docker实例上运行。此外,如果您正在运行Debug LOG-LEVEL,请不要忘记在顶部添加shebang,#!/usr/bin/env python。

3
这对我有用:
FROM docker.io/python:3.7

WORKDIR /app

COPY requirements.txt ./

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

ENV GUNICORN_CMD_ARGS="--bind=0.0.0.0 --chdir=./src/"
COPY . .

EXPOSE 8000

CMD [ "gunicorn", "app:app" ]

-1

gunicorn main:app --workers 4 --bind :3000 --access-logfile '-'

使用gunicorn启动应用程序,绑定在端口3000上,使用4个工作进程,并将访问日志输出到标准输出。


10
请在回答中添加更多细节,尝试解释提问者做错了什么以及为什么你的解决方案有效。谢谢。 - EnriqueBet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接