Docker使用Django迁移组合入口点和CMD

Docker使用Django迁移组合入口点和CMD,django,docker,docker-compose,Django,Docker,Docker Compose,我一直在试图找到最好的方法来处理与Docker建立Django项目的问题。但是我对CMD和ENTRYPOINT如何与compose命令相关感到有些困惑 当我第一次设置项目时,我需要为数据库运行createsuperuser并进行迁移。我曾尝试使用脚本将这些命令作为Dockerfile中的入口点来运行,但似乎效果并不一致。我切换到如下所示的配置,在这里,我用compose文件中的命令覆盖Dockerfile CMD,并告诉它运行makemigrations、migrate和createsuperu

我一直在试图找到最好的方法来处理与Docker建立Django项目的问题。但是我对CMD和ENTRYPOINT如何与compose命令相关感到有些困惑

当我第一次设置项目时,我需要为数据库运行createsuperuser并进行迁移。我曾尝试使用脚本将这些命令作为Dockerfile中的入口点来运行,但似乎效果并不一致。我切换到如下所示的配置,在这里,我用compose文件中的命令覆盖Dockerfile CMD,并告诉它运行makemigrations、migrate和createsuperuser

我现在的问题是如何设置它,使它满足我的需要。如果我在我的compose文件中设置了一个命令(如代码中注释所示),根据我的理解,它应该会覆盖Dockerfile中的CMD

我不确定的是我是否需要在Dockerfile中使用ENTRYPOINT或CMD来实现这一点?由于CMD被我的compose文件覆盖,而ENTRYPOINT没有覆盖,如果将其设置为ENTRYPOINT,会不会导致问题,因为它会在compose命令执行后第二次尝试运行gunicorn

与使用入口点脚本相比,这种方法会有任何缺点吗

最后,在部署停靠的Django应用程序时,是否有处理Django的setup命令的通用最佳实践方法?或者我已经在做通常做的事情了

这是我的Dockerfile:

FROM python:3.6
LABEL maintainer x@x.com

ARG requirements=requirements/production.txt
ENV DJANGO_SETTINGS_MODULE=site.settings.production_test

WORKDIR /app

COPY manage.py /app/
COPY requirements/ /app/requirements/ 

RUN pip install -r $requirements

COPY config config
COPY site site
COPY templates templates
COPY logs logs
COPY scripts scripts

EXPOSE 8001

CMD ["/usr/local/bin/gunicorn", "--config", "config/gunicorn.conf", "--log-config", "config/logging.conf", "-e", "DJANGO_SETTINGS_MODULE=site.settings.production_test", "-w", "4", "-b", "0.0.0.0:8001", "site.wsgi:application"]
...
ENTRYPOINT ["entrypoint.sh"]
CMD ["start"]
和我的撰写文件(省略了nginx和postgres部分,因为它们不需要说明问题):

Dockerfile:

FROM python:3.6
LABEL maintainer x@x.com

ARG requirements=requirements/production.txt
ENV DJANGO_SETTINGS_MODULE=site.settings.production_test

WORKDIR /app

COPY manage.py /app/
COPY requirements/ /app/requirements/ 

RUN pip install -r $requirements

COPY config config
COPY site site
COPY templates templates
COPY logs logs
COPY scripts scripts

EXPOSE 8001

CMD ["/usr/local/bin/gunicorn", "--config", "config/gunicorn.conf", "--log-config", "config/logging.conf", "-e", "DJANGO_SETTINGS_MODULE=site.settings.production_test", "-w", "4", "-b", "0.0.0.0:8001", "site.wsgi:application"]
...
ENTRYPOINT ["entrypoint.sh"]
CMD ["start"]
entrypoint.sh将一直执行,而CMD将是它的默认参数()

entrypoint.sh:

if ["$1" = "start"]
then
    /usr/local/bin/gunicorn --config config/gunicorn.conf \
        --log-config config/logging.conf ...
elif  ["$1" = "migrate"]
    # whatever
    python manage.py migrate
fi
现在可以做类似的事情了

version: "3.2"
services:
  app:
    restart: always
    build:
      ...
    command: migrate # if needed

docker exec-it bash-c entrypoint.sh migrate

我有以下入口点脚本,将尝试在Django项目上自动执行迁移:

#!/bin/bash -x

python manage.py migrate --noinput || exit 1
exec "$@"
Dockerfile需要做的唯一更改是添加它并指定入口点。我通常直接将这些行放在CMD指令上:

ADD docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod a+x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]

(请注意,只有在生成环境中的docker-entrypoint.sh文件尚未执行时,才需要chmod)

我添加了
| | exit 1
,以便在迁移因任何原因失败时脚本将停止容器。当通过docker compose启动项目时,在运行此迁移命令时,数据库可能没有100%准备好接受连接。在错误退出方法和docker-compose.yml中已有的
重新启动:always
之间,这将正确处理竞态条件


请注意,我为bash指定的
-x
选项反映了bash正在做什么,我发现这对调试脚本很有帮助。如果您希望减少容器日志中的详细信息,则可以省略该选项。

当使用
docker exec
启动新进程时,不使用入口点脚本。入口点仅在容器启动阶段使用,因此此方法将返回未找到的
migrate
命令。您仍然可以通过指定如下完整命令来使用exec执行迁移:
docker exec-it python manage.py migrate
您是否可以保持CMD不变?如果容器不需要迁移,它还会正常运行gunicorn吗?是的,入口点脚本末尾的exec行执行任何命令。如果不需要迁移,它将返回0并转到该行。还想知道答案以及如何处理makemigrations吗?“只有在生成环境中的docker-entrypoint.sh文件尚未执行时,才需要chmod”。非常有用。能够少写一行运行代码。:-)