【问题标题】:Docker Compose ENTRYPOINT and CMD with Django MigrationsDocker 使用 Django Migrations 编写 ENTRYPOINT 和 CMD
【发布时间】:2019-05-02 22:58:57
【问题描述】:

我一直在尝试寻找使用 Docker 设置 Django 项目的最佳方法。但是对于 CMD 和 ENTRYPOINT 与 compose 命令的关系,我有些困惑。

当我第一次设置项目时,我需要运行 createsuperuser 并迁移数据库。我尝试使用脚本将命令作为 Dockerfile 中的入口点运行,但它似乎并不能始终如一地工作。我切换到下面显示的配置,在我的 compose 文件中使用命令覆盖 Dockerfile CMD,告诉它运行 makemigrations、migrate 和 createsuperuser。

我遇到的问题是如何设置它,以便它满足我的需要。如果我在撰写文件中设置命令(如代码中注释掉的那样),它应该根据我的理解覆盖我的 Dockerfile 中的 CMD。

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

与使用入口点脚本相比,这种方法有什么缺点吗?

最后,在部署 dockerized Django 应用程序时,是否有一种通用的最佳实践方法来处理 Django 的设置命令?还是我已经在做通常做的事情?

这是我的 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"]

还有我的 compose 文件(省略了 nginx 和 postgres 部分,因为它们对于说明问题没有必要):

version: "3.2"
services:
  app:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile.prodtest
      args:
        requirements: requirements/production.txt
    #command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn --config gunicorn.conf --log-config loggigng.conf -e DJANGO_SETTINGS_MODULE=site.settings.production_test -W 4 -b 0.0.0.0:8000 site.wsgi"
    container_name: dj01
    environment:
      - DJANGO_SETTINGS_MODULE=site.settings.production_test
      - PYTHONDONTWRITEBYTECODE=1
    volumes:
      - ./:/app
      - /static:/static
      - /media:/media
    networks:
      - main
    depends_on:
      - db

【问题讨论】:

    标签: django docker docker-compose


    【解决方案1】:

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

    #!/bin/bash -x
    
    python manage.py migrate --noinput || exit 1
    exec "$@"
    

    唯一需要对 Dockerfile 进行的更改是添加它并指定 ENTRYPOINT。我通常把这几行直接放在 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 中的 restart: always 之间,这将正确处理该竞争条件。

    请注意,我为 bash 指定的 -x 选项呼应了 bash 正在做什么,我发现这对调试我的脚本很有帮助。如果您希望容器日志中的详细程度较低,可以省略它。

    【讨论】:

    • 你会保持 CMD 不变吗?如果不需要迁移,容器是否仍会正常运行 gunicorn?
    • 是的,入口点脚本末尾的 exec 行执行任何命令。如果它不需要迁移,它会返回 0 并继续该行。
    • 也想知道这个问题的答案以及您将如何处理 makemigrations?
    • "只有在构建环境中的 docker-entrypoint.sh 文件还不能执行时才需要 chmod"。非常有帮助。能够少写一条 RUN 行。 :-)
    【解决方案2】:

    Dockerfile:

    ...
    ENTRYPOINT ["entrypoint.sh"]
    CMD ["start"]
    

    entrypoint.sh 将一直执行,而 CMD 将是它的默认参数 (docs)

    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 <container> bash -c entrypoint.sh migrate
    

    【讨论】:

    • An ENTRYPOINT script is not 在以docker exec 启动新进程时使用该entrypoint 仅在容器启动阶段使用,因此这种方法会返回一个command not found为migrate。您仍然可以通过指定完整的命令来使用 exec 进行迁移:docker exec -it &lt;container&gt; python manage.py migrate
    猜你喜欢
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    相关资源
    最近更新 更多