使用 Gunicorn 在 Docker 中使用 Django 开发自动重新加载代码更改

Auto-reloading of code changes with Django development in Docker with Gunicorn

我正在使用 Docker 容器进行 Django 开发,该容器运行带有 Nginx 的 Gunicorn。我希望代码更改能够自动加载,但让它们加载的唯一方法是使用 docker-compose (docker-compose build) 进行重建。 "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),但代码不会刷新。

我错过了什么?

感谢 kikicarbonell,我研究了我的代码的卷,在查看 Docker Compose recommended Django setup 之后,我将 volumes: - .:/code 添加到 docker-[= 中的 Web 容器中34=],现在我所做的任何代码更改都会自动应用。

## 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

更新: 了解将 Gunicorn 和 Django 与 Docker 一起使用的完整示例,请查看此 example project from Rackspace,其中还展示了如何使用 [=35] =]-machine 在 Rackspace Cloud 等远程服务器上启动设置。

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

您还有另一个问题 - 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 安装行无效!

由于我从未找到理想的解决方案,请考虑这个有趣的 hack。在这里发帖我想看看是否有人 similar/good/bad 有这方面的经验 "work around".

为了在本地重新加载代码以进行开发,我只是创建了一个立即调用 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

我希望这对其他人有帮助 and/or 得到对这种方法的反馈。

我在尝试使用稍微不同的设置配置项目的自动重新加载时遇到了非常相似的问题。我设置了音量,但无论如何它都不起作用。经过一个小时的谷歌搜索和彻底检查我的代码后,我发现 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:", ); print "so:"  }' \
        | 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"

我你用docker-compose:

  1. Docker文件:当你从Docker文件构建图像时,你需要添加一些目录来保存你的代码(在我的案例 /api/):

    WORKDIR /api/ -> 重要

    COPY . . -> 重要

  1. Docker-compose:您的 docker-compose 文件为您提供应用程序服务,其中 django 中的图像刚刚从 Docker 文件构建,现在您需要添加与在 Dockerfile:
  2. 中使用的 WORKDIR 相同的卷

volumes: - .:/app -> 重要

这就是全部。

创建卷时,您似乎需要在 docker-compose.yml 中匹配 Dockerfile 中的 WORKDIR/COPY 命令。这是一个例子:

Docker 文件

WORKDIR /app
COPY . /app

docker-compose.yml

app:
    / other commands / 
    volumes:
      - ./app:/app