【问题标题】:Gunicorn does not run in docker container when using ENTRYPOINT or CMD使用 ENTRYPOINT 或 CMD 时 Gunicorn 不在 docker 容器中运行
【发布时间】:2018-10-21 07:12:31
【问题描述】:

我有以下 Dockerfile 和 entrypoint.sh 脚本。我按照下面的方式进行操作,但是当我运行容器时,gunicorn 似乎永远不会启动,因为没有任何内容写入日志文件。容器仍在运行,因为我键入“docker ps”并且可以看到它。

然后我通过执行“docker exec -it /bin/bash”启动一个 bash 进程,我可以从那里运行 gunicorn 进程,然后它就可以工作了。

所以基本上,如果我运行容器然后登录到 bash 会话并粘贴 gunicorn 命令,它就可以工作,但否则它就不会工作。

Dockerfile:

FROM ubuntu:18.04
MAINTAINER peter griffin "some@email.com"
RUN apt-get update -y && apt-get install -y python-pip python-dev

WORKDIR /deploy

COPY ./requirements.txt ./
RUN pip install -r requirements.txt
RUN pip install gunicorn

COPY ./app ./app

COPY [\
    "run.py", \
    "app.db", \
    "entrypoint.sh", \
    "config.py", \
    "gunicorn.conf.py", \
    "./"]

#RUN mkdir ./logs
RUN chmod +x ./entrypoint.sh

ENTRYPOINT ["sh", "entrypoint.sh"]

入口点.sh:

#!/bin/bash

mkdir -p /deploy/logs
touch /deploy/logs/error.log
touch /deploy/logs/access.log
tail -n 0 -f /deploy/logs/*.log

exec gunicorn run:app \
    --name greg_docker \
    --bind 0.0.0.0:8080 \
    --workers 2 \
    --log-level=info \
    --log-file=/deploy/logs/error.log \
    --access-logfile=/deploy/logs/access.log \

构建:

docker build -t greg:latest .

运行:

docker run -d -p 8080:8080 greg:latest

如果我在 /bin/bash 会话中的容器内,我可以粘贴:

exec gunicorn run:app \
    --name greg_docker \
    --bind 0.0.0.0:8080 \
    --workers 2 \
    --log-level=info \
    --log-file=/deploy/logs/error.log \
    --access-logfile=/deploy/logs/access.log

然后当我在 docker 主机上转到 http://0.0.0.0:8080 时它确实有效。

有什么区别?为什么 gunicorn 在 entrypoint.sh 上不起作用?

更新 我创建了一个新文件 entrypoint2.sh:

#!/bin/bash
mkdir -p /deploy/logs
touch /deploy/logs/error.log
exec gunicorn run:app \
    --name greg_docker \
    --bind 0.0.0.0:8080 \
    --log-level=debug \
    --log-file=/deploy/logs/error.log \
    --workers 2
"$@"

我已经更新了我的 Dockerfile:

ENTRYPOINT ["sh","-x","entrypoint2.sh"]

当我运行容器时,我得到了这个:

+ mkdir -p /deploy/logs
+ touch /deploy/logs/error.log
+ exec gunicorn run:app --name greg_docker --bind 0.0.0.0:8080 --log-level=debug --log-file=/deploy/logs/error.log --workers 2

但是容器没有做任何事情,它不会继续运行。

【问题讨论】:

  • 尝试docker exec进入容器,然后运行sh -x entrypoint.sh。这将重新运行入口点脚本并在执行之前打印出每个命令。我猜在您到达exec gunicorn 之前,那里的命令之一不会返回。
  • 好的,我已经进行了上述更改,但仍然无法正常工作。我还尝试使用该尾部命令“tail -n 0 -f /deploy/logs/*.log”,它允许容器继续运行,然后我执行 docker exec /bin/bash,并从那里运行 entrypoint2.sh ,这确实有效。您认为这与权限或组有关吗?
  • 您的gunicorn.conf.py 中有什么内容?
  • 如下:daemon = True accesslog = "logs/access.log" errorlog = "logs/error.log"
  • 但我不再在 entrypoint2.sh 中使用 gunicorn.conf.py 文件

标签: docker flask gunicorn


【解决方案1】:

当您docker run 一个容器时,它会启动 ENTRYPOINT(如果有),将 CMD 作为命令行参数传递给它。当该程序或脚本完成时,容器退出。

在您的第一次迭代中,您的 ENTRYPOINT 说:

#!/bin/bash

# Read all of the log files, blocking forever, printing out new
# content as it appears
tail -n 0 -f /deploy/logs/*.log

# Only then, once that "blocking forever" has finished...
exec gunicorn run:app

所以tail 命令阻止了gunicorn 实际启动。您应该能够通过使用 shell -x 选项(如在您的编辑中,或通过在脚本中添加 set -x 行)看到这一点:它将到达 tail,然后停止。

在评论中您说您在配置文件中设置了daemon = True gunicorn option。如果 gunicorn 发现了这一点,它就会将自己分叉到后台并退出。从 Docker 的角度来看,它将启动的进程视为容器入口点出口,因此容器完成,然后关闭。我不完全确定是什么导致或不是导致该配置文件被读取,但这会导致提前退出。

您需要确保将服务器作为前台进程运行。如果您 docker exec 在正在运行的容器中获取 shell,启动服务器并返回命令提示符,那么您调用它的方式不会使容器保持活动状态。

【讨论】:

  • 我认为“exec”命令可能是罪魁祸首,因为我读取它替换了当前进程,而在其他地方我读取如果 PID 1 不存在,docker 容器停止运行。
【解决方案2】:

原来运行gunicorn的时候,你绝对需要指定一个配置文件。

entrypoint2.sh:

#!/bin/bash
mkdir -p /deploy/logs
touch /deploy/logs/error.log
touch /deploy/logs/access.log
cd /deploy
exec gunicorn --bind 0.0.0.0:8080 -c docker-gunicorn.conf.py run:app

docker-gunicorn.conf.py:

accesslog = "/deploy/logs/access.log"
errorlog = "/deploy/logs/error.log"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-14
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 2022-07-19
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    相关资源
    最近更新 更多