запуск django worker и daphne в док-контейнере

У меня есть приложение django, которое запускается в контейнере докеров. Недавно я понял, что мне нужно добавить интерфейс веб-сокетов в свое приложение. Я использую каналы с daphne за nginx и redis в качестве кеша. Проблема в том, что мне нужно запустить django worker и daphne в 1 контейнере. Скрипт, который запускается при запуске контейнера:

#!/usr/bin/env bash

python wait_for_postgres.py
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --no-input

python manage.py runworker --only-channels=http.* --only-channels=websocket.* -v2
daphne team_up.asgi:channel_layer --port 8000 -b 0.0.0.0

Но зависает на запуске воркера. Я пробовал nohup, но, похоже, он не работает. Если я запускаю daphne напрямую из контейнера с помощью docker exec, все работает нормально.


person Quba    schedule 19.06.2016    source источник
comment
Вам удалось решить проблему? Я правильно понимаю, что Дафна виснет? У меня такая же проблема каждый раз, когда мне нужно перезапустить Дафну, я убиваю процесс и запускаю его снова   -  person arminrock    schedule 07.07.2016
comment
Ага. Я использовал supervisord со следующей конфигурацией: pastebin.com/uS7SfU5L и при запуске контейнера supervisord -c ./supervisord .conf   -  person Quba    schedule 14.07.2016
comment
Вы блокируете сервер daphne выполнением рабочего процесса. Запустите worker и контейнер в отдельных контейнерах (пример кода: github.com/pplonski/simple-tasks)   -  person pplonski    schedule 25.10.2018


Ответы (1)


Это старый вопрос, но я решил, что все равно отвечу на него, потому что недавно столкнулся с той же проблемой и подумал, что могу пролить свет на это.

Как работают каналы Django

Каналы Django — это еще один уровень поверх Django, который имеет два типа процессов:

  • Тот, который принимает HTTP/веб-сокеты
  • Тот, который запускает представления Django, обработчики веб-сокетов, фоновые задачи и т. д.

По сути, когда приходит запрос, он сначала попадает на интерфейсный сервер (Daphne), который принимает соединение HTTP/Websocket и помещает его в очередь Redis. Затем рабочий (потребитель) видит его, убирает из очереди и запускает логику представления (например, представления Django, обработчики WS и т. д.).

Почему это не сработало для вас

Потому что вы запускаете только рабочего (потребителя), и он блокирует выполнение интерфейса сервера (производителя). Это означает, что никакие соединения не будут приниматься, а рабочий просто смотрит на пустую очередь Redis.

Как я заставил это работать

Я запускаю Daphne, Redis и Workers как отдельные контейнеры для легкого масштабирования. Миграции БД, сбор статических файлов и т. д. выполняются только в контейнере Daphne. В этом контейнере будет работать только один экземпляр, чтобы гарантировать отсутствие параллельных миграций БД.

Рабочие, с другой стороны, могут масштабироваться вверх и вниз для обработки входящего трафика.

Как заставить это работать

Разделите установку на как минимум два контейнера. Я бы не рекомендовал запускать все в одном контейнере (например, используя Supervisor). Почему? Потому что, когда приходит время масштабировать установку, нет простого способа сделать это. Вы можете масштабировать свой контейнер до двух экземпляров, но это просто создаст еще один супервизор с daphne, redis, django в нем... если вы отделите рабочего от daphne, вы можете легко масштабировать рабочий контейнер для обработки растущих входящих запросов.

Один контейнер может работать:

#!/usr/bin/env bash

python wait_for_postgres.py
python manage.py migrate
python manage.py collectstatic --no-input

daphne team_up.asgi:channel_layer --port 8000 -b 0.0.0.0

в то время как другой:

#!/usr/bin/env bash

python wait_for_postgres.py
python manage.py runworker --only-channels=http.* --only-channels=websocket.* -v2

Команда makemigrations

Нет необходимости запускать команду в предоставленном вами сценарии, если что-то может заблокировать все это из-за какого-то вопроса, для которого он ожидает ввода (например, «Вы переименовали столбец X в Y?»).

Вместо этого вы можете выполнить его в работающем контейнере следующим образом:

docker exec -it <container_name> python manage.py makemigrations
person roman    schedule 14.02.2017