Запуск каналов django с daphne на systemd

Прежде всего, извините за длинный вопрос, я надеюсь, что у некоторых из вас хватит на это терпения.

TL; ДР: Как мне правильно загрузить настройки django в systemd?

Я следую этому руководству, Развертывание каналов Django с помощью Дафны, поэтому я могу запускать некоторые приложения в реальном времени (используя WebSockets). Без nginx и при запуске из командной строки рабочего (python manage.py runworker) и интерфейса (daphne) я могу получить доступ к правильному классу потребителей каналов, как можно увидеть в журнале ниже (они были запущены из клиента javascript) :

2017-10-09 21:10:35,210 - DEBUG - worker - Got message on websocket.connect (reply daphne.response.CYeWgnNQoY!mwuQrazQtv)
2017-10-09 21:10:35,211 - DEBUG - runworker - websocket.connect
2017-10-09 21:10:35,211 - DEBUG - worker - Dispatching message on websocket.connect to api.consumers.OrderConsumer
2017-10-09 21:10:48,132 - DEBUG - worker - Got message on websocket.receive (reply daphne.response.CYeWgnNQoY!mwuQrazQtv)
2017-10-09 21:10:48,132 - DEBUG - runworker - websocket.receive
2017-10-09 21:10:48,132 - DEBUG - worker - Dispatching message on websocket.receive to api.consumers.OrderConsumer

Эти события были вызваны следующими вызовами javascript:

ws = new WebSocket("ws://localhost:8000/order/1/")
ws.send("test")

С nginx и запуском интерфейса и worker на systemd я получаю следующий журнал, несмотря на то, что использую тот же самый ввод триггера.

2017-10-09 20:38:35,503 - DEBUG - worker - Got message on websocket.connect (reply daphne.response.PPGuXtBmQD!EgUfaNZjUj)
2017-10-09 20:38:35,503 - DEBUG - runworker - websocket.connect
2017-10-09 20:38:35,503 - DEBUG - worker - Dispatching message on websocket.connect to channels.routing.connect_consumer
2017-10-09 20:38:42,993 - DEBUG - worker - Got message on websocket.receive (reply daphne.response.PPGuXtBmQD!EgUfaNZjUj)
2017-10-09 20:38:42,993 - DEBUG - runworker - websocket.receive
2017-10-09 20:38:42,993 - DEBUG - worker - Dispatching message on websocket.receive to channels.routing.null_consumer

Обратите внимание, что канал приема направляется на null_consumer. Я считаю, что проблема здесь просто в том, что channels.routing плохо настроен. Поскольку я использую один и тот же параметр (файл настроек Django) в обеих версиях, это, вероятно, означает, что сам параметр загружается неправильно. Обратите внимание на следующие файлы.

## rest-api/farmaApp/settings.py

...
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'asgi_redis.RedisChannelLayer',
        'CONFIG': {
            'hosts': [('localhost', 6379)],
        },
        'ROUTING': 'farmaApp.routing.channel_routing',
    }
}
...

Что должно настроить channels.routing на:

## rest-api/farmaApp/routing.py

from channels.routing import route
from api.consumers import ws_connect, ws_disconnect, OrderConsumer

channel_routing = [
    route('websocket.connect', ws_connect, path=r'^/users/'),
    route('websocket.disconnect', ws_disconnect, path=r'^/users/'),
    OrderConsumer.as_route(path=r'^/order/(?P<order_id>[\d+])/'),
]

Опять же, я не думаю, что сама конфигурация неправильная, поскольку она работает без systemd. Наконец, вот мои системные конфигурации:

## /etc/systemd/system/daphne.service

[Unit]
Description=daphne daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/rest-api
Environment=DJANGO_SETTINGS_MODULE=farmaApp.settings
ExecStart=/home/ubuntu/rest-api/env/bin/daphne --access-log /home/ubuntu/rest-api/access.log -b 0.0.0.0 -p 8001 farmaApp.asgi:channel_layer

[Install]
WantedBy=multi-user.target


## /etc/systemd/system/django_worker.service
[Unit]
Description=django_worker daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/rest-api
Environment=DJANGO_SETTINGS_MODULE=farmaApp.settings
ExecStart=/home/ubuntu/rest-api/env/bin/python manage.py runworker -v 2

[Install]
WantedBy=multi-user.target

Обратите внимание на оба файла конфигурации, которые я экспортирую в среду, переменную DJANGO_SETTINGS_MODULE в соответствии со связанным руководством. Я считаю, что это работает не так, как ожидалось.


person jhc    schedule 09.10.2017    source источник
comment
У меня была аналогичная проблема, и я переключился на supervisord, но все же мне пришлось перечислить полный набор env vars в файле conf. Я слишком легко сдался, поэтому, если у вас все получится, опубликуйте, как вы это сделали, с помощью общего файла Environment. Я пытался использовать Директива EnvironmentFile - возможно, у вас получится заставить это работать.   -  person AMG    schedule 10.10.2017
comment
[не обращайте внимания на то, что он у вас там есть - игнорируйте этот комментарий] или, возможно, вам нужно установить WorkingDirectory = / path / to / farmaApp в разделе службы daphne.   -  person AMG    schedule 10.10.2017
comment
@AMG с супервизором работало? Я могу попробовать это вместо этого.   -  person jhc    schedule 10.10.2017


Ответы (3)


Я только что развернул свое приложение канала django, и следующий служебный файл systemd работал у меня без использования супервизора:

/etc/systemd/system/django-channels-daphne.service

[Unit]
Description=daphne server script for my project
After=network.target

[Service]
User=webuser
Group=webuser
WorkingDirectory=/path/to/myproject
Environment=DJANGO_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Environment=DJANGO_ALLOWED_HOSTS=myapp.chatbot.ai
ExecStart=/path/to/python/virtualenv/bin/daphne -b 0.0.0.0 -p 8000 myproject.asgi:channel_layer
Restart=always

[Install]
WantedBy=multi-user.target

/etc/systemd/system/django-channels-runworker.service

[Unit]
Description=python runworker server for myproject
After=network.target

[Service]
User=webuser
Group=webuser
WorkingDirectory=/path/to/myproject
Environment=DJANGO_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Environment=DJANGO_ALLOWED_HOSTS=myapp.chatbot.ai
ExecStart=/path/to/python/virtualenv/bin/python /path/to/myproject/manage.py runworker --threads 4 
Restart=always

[Install]
WantedBy=multi-user.target

/path/to/myproject/myproject/asgi.py

import os
import channels

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
channel_layer = channels.asgi.get_channel_layer()

Некоторые строки в /path/to/myproject/myproject/settings.py:

ALLOWED_HOSTS = [os.environ['DJANGO_ALLOWED_HOSTS']]
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
person wyde    schedule 23.11.2017
comment
Какова цель размещения DJANGO_SECRET_KEY и DJANGO_ALLOWED_HOSTS в файле daphne.service? - person Darwin; 14.02.2018
comment
@Darwin - чтобы избежать его в системе контроля версий или необходимости устанавливать его глобально в среде веб-пользователя. - person Richard de Wit; 23.01.2020
comment
Есть и другие способы сделать это. Примечательно, что python-dotenv файл позволяет вам указать путь к файлу .env внутри вашего django settings.py. Я просто добавляю .env к .gitignore и включаю его в сценарий. Затем я chmod 600 .env заблокировал его. - person Cal Abel; 30.04.2021

Да, супервайзер сработал. Ключевые биты /etc/supervisor/conf.d/project_name.conf были (некоторые дополнительные ссылки в прокомментированных частях):

[program:platform_asgi_daphne]
; # https://stackoverflow.com/questions/17055951/how-to-set-environment-variables-in-supervisor-service
; # https://github.com/django/daphne/pull/37
; # https://wiki.cac.washington.edu/display/infra/Extracting+Certificate+and+Private+Key+Files+from+a+.pfx+File
; # daphne -e ssl:8443:privateKey=localhost.key:certKey=localhost.crt <channel_layer>
environment =
    DJANGO_SECRET_KEY='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    DJANGO_DEBUG='True'
directory=/path/to/project/
; # http://channels.readthedocs.io/en/stable/deploying.html
; command=/path/to/venv/bin/daphne --port 80 --bind 0.0.0.0 classact.asgi:channel_layer
command=/path/to/venv/bin/daphne -e ssl:443:privateKey=../keys/server.key:certKey=../keys/server.crt --bind 0.0.0.0 projectfoldername.asgi:channel_layer
;user=webapps
;group=webapps
user=root
group=webapps

[program:platform_asgi_workers]
; # https://github.com/django/channels/issues/408#issuecomment-276384104
environment =
    DJANGO_SECRET_KEY='xxxxxxxxxxxxxxxxxxxxxxxxx',
    DJANGO_DEBUG='True'
command=/path/to/venv/bin/python /path/to/project/manage.py runworker
process_name=asgi_worker%(process_num)s
numprocs=2
;user=webapps
user=root
group=webapps

У меня было несколько проблем, связанных с пользовательскими веб-приложениями, которые еще предстоит разобрать, поэтому они запускаются как root (запись в зашифрованную папку с нечетными разрешениями). Я не дошел до того, что не повторял кучу переменных окружения в каждом разделе (вероятно, способ есть). Есть несколько других, таких как база данных, пользователь, статический корень и т. Д., В зависимости от платформы (prod или dev).

У меня также есть некоторые сертификаты, с которыми нужно иметь дело, чтобы это тоже было показано (если не требуется, выньте части ssl). Также обратите внимание на запуск двух рабочих.

person AMG    schedule 11.10.2017

В ваших опубликованных конфигах порт дафны вроде отключен.

вы написали:

ws = new WebSocket("ws://localhost:8000/order/1/")
ws.send("test")`

при использовании 8001 в файле запуска systemd

ExecStart=/home/ubuntu/rest-api/env/bin/daphne --access-log /home/ubuntu/rest-api/access.log -b 0.0.0.0 -p 8001 farmaApp.asgi:channel_layer
person harmv    schedule 21.02.2018