Автоматическая перезагрузка изменений кода с развитием Django в Docker с Gunicorn

Я использую контейнер Docker для разработки Django, и контейнер запускает Gunicorn с Nginx. Я бы хотел, чтобы изменения кода были загружены автоматически, но единственный способ загрузить их - это перестроить с помощью docker-compose (docker-compose build). Проблема с "сборкой" заключается в том, что она повторно запускает все мои установки папок.

Я использую флаг 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 restart, docker-compose up), но код не обновляется.

Что мне не хватает?

Ответ 1

Благодаря kikicarbonell я заглянул в объем для моего кода и после просмотра Docker Compose рекомендовал настройку Django, я добавил volumes: - .:/code в мой веб-контейнер в docker-compose.yml, и теперь любые изменения кода, которые я делаю, автоматически применяются.

## 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, посмотрите этот пример проекта из Rackspace, в котором также показано, как использовать докеры -machine для запуска установки на удаленных серверах, таких как Rackspace Cloud.

Предостережение:, этот метод не работает, когда ваш код локально, а хост докера удален (например, у облачного провайдера, такого как Digital Ocean или Rackspace). Это также относится к виртуальным машинам, если ваша локальная файловая система не установлена ​​на виртуальной машине. Обратите внимание, что есть отдельные драйверы томов (например, flocker), и может быть что-то там, чтобы удовлетворить эту потребность. На данный момент "fix" - это rsync/scp ваши файлы до каталога на удаленном узле докера. Затем флаг --reload будет автоматически перезагружать бункер после любого scp/rsync. Обновление:. Если вы нажимаете код для удаления узла докеров, мне гораздо проще просто перестроить контейнер докера (например, docker-compose build web && docker-compose up -d). Это может быть медленнее, чем подход rsync, если ваша папка src большая.

Ответ 2

У вас еще одна проблема - Docker кэширует каждый слой, который он создает. Вам не нужно повторно запускать установку pip каждый раз!

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/

Это приведет к недействительности вашей линии установки пакета, если ваш файл требований изменится!

Ответ 3

Поскольку я так и не нашел желаемого решения, рассмотрим этот интересный взлом. Публикуя здесь, я хотел посмотреть, есть ли у кого-нибудь подобные/хорошие/плохие опыты с этим "обходным путем".

Чтобы сделать перезагрузку кода локально для разработки, я просто создал View, который немедленно вызывает 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

Я надеюсь, что это поможет другим и/или получит обратную связь от этого подхода.