【问题标题】:Auto-reloading of code changes with Django development in Docker with Gunicorn使用 Gunicorn 在 Docker 中使用 Django 开发自动重新加载代码更改
【发布时间】:2015-11-08 09:57:59
【问题描述】:

我正在使用 Docker 容器进行 Django 开发,该容器使用 Nginx 运行 Gunicorn。我希望将代码更改为自动加载,但我可以让它们加载的唯一方法是使用 docker-compose (docker-compose build) 进行重建。 “构建”的问题在于它重新运行了我所有的 pip 安装。

我正在使用 Gunicorn --reload 标志,这显然应该做我想做的事。这是我的 Docker 配置文件:

## Dockerfile:
FROM python:3.4.3
RUN mkdir /code
WORKDIR /code
ADD . /code/
RUN pip install -r /code/requirements/docker.txt

## docker-compose.yml:
web:
  restart: always
  build: .
  expose:
    - "8000"
  links:
    - postgres:postgres
  volumes:
    - /usr/src/app/static
  env_file: .env
  command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload

nginx:
  restart: always
  build: ./config/nginx
  ports:
    - "80:80"
  volumes:
    - /www/static
  volumes_from:
    - web
  links:
    - web:web

postgres:
  restart: always
  image: postgres:latest
  volumes:
    - /var/lib/postgresql
  ports:
    - "5432:5432"

我尝试了其他一些 Docker 命令(docker-compose restartdocker-compose up),但代码不会刷新。

我错过了什么?

【问题讨论】:

  • 您是否与您的代码共享卷?您可以发布部分 docker-compose.yml 以查看场景吗?
  • 我不明白你的““构建”的问题是它重新运行了我所有的 pip 安装。”也许你可以先安装所有的 pip,这样docker build 只加载代码变化。你能展示你的 Dockerfile 吗?您还可以拥有一个以FROM mypipinstalls 开头的 Dockerfile
  • kikicarbonell,您的问题帮助我意识到我的代码需要一个卷,这似乎解决了我的问题,所以感谢您引导我找到解决方案!
  • @user2915097,虽然我认为我通过添加代码量解决了我的问题,但我很好奇你的建议。 FROM mypipinstalls 将如何工作(即,与我现在所做的相比——见上文,我添加了我的配置文件)?
  • 对于任何后续读者,@user2915097 肯定是在参考多阶段构建。如果您要重建 docker-compose 应用程序,您可以使用它来创建不会更改的图层。但是那样只是为了重新加载代码有点过头了,我建议坚持使用共享卷。

标签: django docker gunicorn docker-compose


【解决方案1】:

感谢 kikicarbonell,我考虑为我的代码创建一个卷,在查看了 Docker Compose recommended Django setup 之后,我在 docker-compose.yml 中将 volumes: - .:/code 添加到我的 Web 容器中,现在我会自动更改任何代码申请。

## docker-compose.yml:
web:
  restart: always
  build: .
  expose:
    - "8000"
  links:
    - postgres:postgres
  volumes:
    - /usr/src/app/static
    - .:/code
  env_file: .env
  command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload

更新: 有关在 Docker 中使用 Gunicorn 和 Django 的完整示例,请查看此 example project from Rackspace,它还展示了如何使用 docker-machine 在 Rackspace Cloud 等远程服务器上启动设置。

警告:目前,当您的代码存储在本地并且 docker 主机位于远程(例如,在 Digital Ocean 或 Rackspace 等云提供商上)时,此方法不起作用。如果您的本地文件系统未安装在 VM 上,这也适用于虚拟机。请注意,有单独的卷驱动程序(例如,flocker),并且可能有一些东西可以满足这种需求。 目前,“修复”是将文件 rsync/scp 到远程 docker 主机上的目录。然后,--reload 标志将在任何 scp/rsync 之后自动重新加载 gunicorn。 更新: 如果将代码推送到远程 docker 主机,我发现重建 docker 容器要容易得多(例如,docker-compose build web && docker-compose up -d)。如果您的 src 文件夹很大,这可能会比 rsync 方法慢。

【讨论】:

  • 我认为 inotify 不适用于 Docker 卷。 github.com/docker/docker/issues/18246知道为什么会这样吗?
  • @EricIhli -- 当 docker 主机位于远程时,此方法不起作用(因为 Compose 文件中的卷声明与 docker 主机相关)。我已经更新了我的答案,并附上了澄清这一点的免责声明。
  • 啊。谢谢。我确实解决了需要监视文件更改并在容器内执行一些操作的问题,方法是在 Mac 上使用“fswatch”,通过管道连接到“xargs”,并运行“docker exec ”,以防其他人正在寻找那个。
  • 我在我的 Mac 上看到了间歇性行为(Docker 和 Django 都是本地的)。有时它会自动重新加载,有时它不会,这使得开发非常困难。以前有人见过这种行为吗? @EricIhli
  • 感谢 gunicorn 的“--reload”,它拯救了我的一天
【解决方案2】:

你还有另一个问题——Docker 缓存它构建的每一层。您不必每次都重新运行 pip install!

ADD . /code/
RUN pip install -r /code/requirements/docker.txt

这是你的问题 - Docker 检查每个 ADD 语句以查看是否有任何文件已更改,并使其缓存无效,如果有,则使其后续步骤无效。正确的做法是……

ADD ./requirements/docker.txt /code/requirements/
RUN pip install -r /code/requirements/docker.txt
ADD ./code/

如果您的需求文件发生更改,这只会使您的 pip install 行无效!

【讨论】:

  • 我想知道为什么 ADD 是多余的。谢谢你告诉我
【解决方案3】:

由于我从未找到理想的解决方案,请考虑这个有趣的 hack。在这里发帖我想看看是否有人对这种“解决方法”有类似/好的/不好的经历。

为了让代码在本地重新加载以进行开发,我只是创建了一个立即调用exit() 的视图。退出将使 Django 崩溃,并在代码更改可用的地方重新加载。重启只需要几分之一秒,可以通过浏览器中的选项卡、requests.get 调用或任何其他类似调用来完成。重新加载不是自动的,但它会跳过任何 Docker 延迟,例如重新启动。

调用退出时,您将看到 PID 增量(如果是拖尾日志):

web    | [2019-07-15 18:29:52 +0000] [22] [INFO] Worker exiting (pid: 22)
web    | [2019-07-15 18:29:52 +0000] [24] [INFO] Booting worker with pid: 24

我希望这对其他人有所帮助和/或得到反馈。

【讨论】:

  • 如果您使用 gunicorn 进行本地开发,--reload 标志将自动使用您的最新代码,假设您的本地代码是从 docker 和本地盒子之间的共享卷中读取的。如果您在使用此设置时遇到问题并想进一步解决,我很乐意帮助您调试问题,但您应该提出一个新问题并链接回这些 cmets。
  • @DolanAntenucci 感谢您的回复。每个项目的设置都不同,所以--reload 并不总是一个选项。这种“变通办法”可能会帮助其他人修补糟糕的情况。
  • @DolanAntenucci,跟进 - 我对标志进行了一些测试,它通常是可靠的,但不是 100%。我觉得 10 次中有 1 次代码没有更新,我需要使用替代方法。 Docker 设置(继承)可能会造成干扰,不确定但再次感谢此项目中的 b/c --reload 通常有效。
  • 感谢您的更新。我确实记得有--reload 不是 100%,但我忘记了是否存在它不起作用的特殊情况。实际上,芹菜工人就是一个例子。需要重启
  • Docker 不是一个标准,所以我很高兴有一个替代方案。 Celery 确实需要“代码重新加载”,因为它是一个与 Python 代码交互的后台应用程序,我记得在 VENV 和 PIPENV 中需要重新启动该服务以进行代码编辑,我希望得到改进,但不便之处很少。
【解决方案4】:

我用的是 docker-compose:

  1. DockerFile:当你从 Dockerfile 构建镜像时,你需要添加一些目录来保存你的代码(在我的例子中是 /api/):

    WORKDIR /api/ -> 重要

    COPY . . -> 重要

  1. Docker-compose:您的 docker-compose 文件为您提供了应用服务,其中包含刚刚从 Dockerfile 构建的 django 中的映像,现在您需要添加具有您在 Dockerfile 中使用的相同 WORKDIR 的卷:

volumes: - .:/app -> 重要

就是这样。

【讨论】:

    【解决方案5】:

    我在尝试使用稍微不同的设置配置项目的自动重新加载时遇到了非常相似的问题。我设置了卷,但它仍然不起作用。经过一个小时的谷歌搜索和彻底检查我的代码后,我发现 Dockerfile 和 docker-compose.yml 中的卷 路径根本不匹配。确保它们相同。

    我的 Dockerfile

    FROM python:3.6.9-alpine3.10
    
    COPY ./requirements/local.txt /app/requirements/local.txt
    
    RUN set -ex \
        && apk add --no-cache --virtual .build-deps postgresql-dev git gcc libgcc musl-dev jpeg-dev zlib-dev build-base \
        && python -m venv /env \
        && /env/bin/pip install --upgrade pip \
        && /env/bin/pip install --no-cache-dir -r /app/requirements/local.txt \
        && runDeps="$(scanelf --needed --nobanner --recursive /env \
            | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
            | sort -u \
            | xargs -r apk info --installed \
            | sort -u)" \
        && apk add --virtual rundeps $runDeps \
        && apk del .build-deps
    
    ### Here is the path to the project
    COPY . /app
    
    WORKDIR /app/project
    
    ENV VIRTUAL_ENV /env
    ENV PATH /env/bin:$PATH
    ENV PYTHONDONTWRITEBYTECODE 1
    ENV PYTHONUNBUFFERED 1
    
    EXPOSE 8088
    
    

    我的 docker-compose.yml

    version: '3'
    
    
    services:
    
      web:
        build:
          context: ../..
          dockerfile: compose/local/Dockerfile
        restart: on-failure
        command: python manage.py runserver 0.0.0.0:8088 --settings=project.settings.local
        volumes:
          # - .:/var/www/app  # messed up path
          - .:/app  # correct path
        env_file:
          - ../../.env.local
        depends_on:
          - db
        ports:
          - "8000:8000"
    

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 2016-04-26
      • 2016-08-26
      • 2013-04-05
      • 2019-06-05
      • 1970-01-01
      • 1970-01-01
      • 2015-12-27
      相关资源
      最近更新 更多