Другое

Развертывание Django Channels с ASGI и Daphne на AWS Elastic Beanstalk с Docker

Полное руководство по развертыванию Django Channels с ASGI и Daphne на AWS Elastic Beanstalk с использованием Docker. Исправление проблем с маршрутизацией трафика с помощью правильной конфигурации прокси NGINX.

Как развернуть Django с Channels + ASGI + Daphne на AWS Elastic Beanstalk с использованием Docker

Я пытаюсь развернуть Django-приложение, использующее Channels + ASGI + Daphne, на AWS Elastic Beanstalk с платформой Docker. Мой контейнер успешно собирается, миграции выполняются, и Daphne корректно запускается на 0.0.0.0:8000. В логах показано, что ASGI-сервер работает без ошибок.

Проблема в том, что Elastic Beanstalk не маршрутизирует трафик на сервер Daphne внутри Docker-контейнера.

Текущее состояние:

  • В логах Docker показано, что Daphne слушает на 0.0.0.0:8000
  • Контейнер запускается чисто (без ошибок)
  • curl :8000/ работает
  • curl http://localhost/ на хосте не достигает Daphne
  • /health/ ничего не возвращал, потому что у Django не было маршрута (исправлено)
  • Среда Elastic Beanstalk загружается, но сайт не отвечает извне
  • Похоже, что NGINX внутри EB не проксирует запросы в контейнер

Что мне нужно:

Мне нужен рабочий пример:

  • Dockerfile
  • entrypoint.sh
  • EB .ebextensions конфигурация для ASGI/Daphne
  • NGINX конфигурация прокси для перенаправления WebSocket + HTTP трафика
  • Любые дополнительные настройки EB, необходимые для Channels

По сути, мне нужна правильная настройка, чтобы Elastic Beanstalk мог перенаправлять весь трафик на Daphne внутри Docker-контейнера.

Развертывание Django с Channels, ASGI и Daphne на AWS Elastic Beanstalk с использованием Docker требует правильной настройки Docker-контейнера, параметров среды Elastic Beanstalk и настройки прокси-сервера NGINX для правильной маршрутизации трафика на ASGI-сервер, работающий внутри Docker-контейнера. Основная проблема, с которой вы сталкиваетесь, заключается в том, что встроенный NGINX Elastic Beanstalk правильно не перенаправляет трафик WebSocket и HTTP на ваш сервер Daphne, работающий внутри Docker-контейнера.

Содержание

Настройка Docker

Dockerfile

Создайте правильный Dockerfile, который устанавливает Daphne и настраивает ваше приложение:

dockerfile
FROM python:3.11-slim

# Установка переменных окружения
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Установка рабочей директории
WORKDIR /app

# Установка системных зависимостей
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        gcc \
        libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# Установка Python-зависимостей
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt

# Копирование проекта
COPY . /app/

# Открытие порта, на котором будет работать Daphne
EXPOSE 8000

entrypoint.sh

Создайте скрипт entrypoint для запуска веб-сервера и Daphne:

bash
#!/bin/bash
set -e

# Выполнение миграций базы данных
python manage.py migrate --noinput

# Сбор статических файлов
python manage.py collectstatic --noinput

# Запуск сервера Daphne
exec daphne -b 0.0.0.0 -p 8000 your_project.asgi:application

Сделайте этот скрипт исполняемым: chmod +x entrypoint.sh

Параметры Elastic Beanstalk

Конфигурация .ebextensions

Создайте .ebextensions/01_daphne.config для правильного запуска Daphne:

yaml
option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: your_project.asgi:application
  aws:elasticbeanstalk:application:environment:
    DJANGO_SETTINGS_MODULE: "your_project.settings"

Создайте .ebextensions/02_daphne_daemon.config:

yaml
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/post/run_supervised_daemon.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/usr/bin/env bash
      # Получение переменных окружения Django
      djangoenv=`cat /opt/python/current/env | tr '\n' ',' | sed 's/%/%%/g' | sed 's/export //g' | sed 's/$PATH/%(ENV_PATH)s/g' | sed 's/$PYTHONPATH//g' | sed 's/$LD_LIBRARY_PATH//g'`
      djangoenv=${djangoenv%?}
      
      # Создание скрипта конфигурации демона
      daemonconf="[program:daphne]
      ; Установите полный путь к программе channels, если используете virtualenv
      command=/opt/python/run/venv/bin/daphne -b 0.0.0.0 -p 8000 your_project.asgi:application
      directory=/opt/python/current/app
      user=ec2-user
      numprocs=1
      stdout_logfile=/var/log/stdout_daphne.log
      stderr_logfile=/var/log/stderr_daphne.log
      autostart=true
      autorestart=true
      startsecs=10
      ; Необходимо дождаться завершения выполняемых задач при выключении."
      
      # Запись файла конфигурации
      echo "$daemonconf" | tee /etc/supervisor/conf.d/daphne.conf
      
      # Обновление supervisor
      supervisorctl update
      supervisorctl start daphne

Конфигурация Dockerrun.aws.json

Для развертывания на основе Docker создайте Dockerrun.aws.json:

json
{
  "AWSEBDockerrunVersion": "2",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "your-registry/your-app:latest",
      "essential": true,
      "memory": 128,
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 8000
        }
      ],
      "environment": [
        {
          "name": "DJANGO_SETTINGS_MODULE",
          "value": "your_project.settings"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/aws/elasticbeanstalk/your-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "web"
        }
      }
    }
  ]
}

Настройка ASGI-приложения

Создайте файл вашего ASGI-приложения (например, your_project/asgi.py):

python
import os
import django
from channels.routing import get_default_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
django.setup()

application = get_default_application()

Для Channels 2.x может потребоваться более подробная конфигурация:

python
import os
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
django_asgi_app = get_asgi_application()

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from your_app.routing import websocket_urlpatterns

application = ProtocolTypeRouter({
    "http": django_asgi_app,
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
    ),
})

Настройка прокси-сервера NGINX

.ebextensions/nginx.config

Создайте .ebextensions/nginx.config для настройки прокси-сервера NGINX:

yaml
files:
  "/etc/nginx/conf.d/proxy.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      upstream webapp {
          server 127.0.0.1:8000;
      }
      
      server {
          listen 80;
          
          location / {
              proxy_pass http://webapp;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
          }
          
          location /ws/ {
              proxy_pass http://webapp;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
          }
      }
      
      location /static/ {
              alias /static/;
      }
      
      location /media/ {
              alias /media/;
      }

Эта конфигурация:

  • Маршрутизирует HTTP-трафик на порт 8000
  • Обрабатывает обновления WebSocket
  • Правильно передает заголовки
  • Отдает статические и медиафайлы

Полный рабочий пример

Вот полный рабочий набор на основе результатов исследований:

Структура директорий

your_project/
├── .ebextensions/
│   ├── 01_daphne.config
│   ├── 02_daphne_daemon.config
│   └── nginx.config
├── Dockerfile
├── entrypoint.sh
├── Dockerrun.aws.json
├── requirements.txt
└── your_project/
    ├── asgi.py
    ├── settings.py
    └── ...

Ключевые файлы

requirements.txt:

Django>=4.2.0
channels>=4.0.0
daphne>=4.0.0
redis>=5.0.0
...

your_project/asgi.py (упрощенная рабочая версия):

python
import os
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
django_asgi_app = get_asgi_application()

application = django_asgi_app

entrypoint.sh (финальная версия):

bash
#!/bin/bash
set -e

# Выполнение миграций базы данных
python manage.py migrate --noinput

# Сбор статических файлов
python manage.py collectstatic --noinput

# Запуск сервера Daphne
echo "Запуск сервера Daphne..."
exec daphne -b 0.0.0.0 -p 8000 your_project.asgi:application

Конфигурация Elastic Beanstalk

.ebextensions/01_daphne.config:

yaml
option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: your_project.asgi:application
  aws:elasticbeanstalk:application:environment:
    DJANGO_SETTINGS_MODULE: "your_project.settings"

.ebextensions/nginx.config:

yaml
files:
  "/opt/elasticbeanstalk/hooks/confighooks/post/99_nginx_proxy.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash
      # Настройка NGINX для проксирования на Daphne
      cat >> /etc/nginx/conf.d/elasticbeanstalk/health.conf << EOF
      location /health {
          proxy_pass http://127.0.0.1:8000/health;
          proxy_set_header Host \$host;
          proxy_set_header X-Real-IP \$remote_addr;
          proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto \$scheme;
      }
      EOF
      
      # Перезапуск NGINX
      nginx -s reload

Устранение распространенных проблем

Проблема 1: Ошибки проверок работоспособности

Проблема: Проверки работоспособности Elastic Beanstalk не проходят, потому что Daphne не отвечает на запросы /health.

Решение: Добавьте конечную точку проверки работоспособности в ваши представления Django:

python
# your_project/views.py
from django.http import JsonResponse

def health_check(request):
    return JsonResponse({"status": "healthy"})

Добавьте ее в URL-адреса:

python
# your_project/urls.py
from django.urls import path
from .views import health_check

urlpatterns = [
    path('health/', health_check, name='health'),
    # ... другие URL-адреса
]

Проблема 2: Сбои подключений WebSocket

Проблема: Подключения WebSocket не работают из-за проблем с конфигурацией прокси.

Решение: Убедитесь, что ваша конфигурация NGINX включает правильные заголовки WebSocket:

nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Проблема 3: Конфликты портов

Проблема: Daphne запускается на порту 8000, но Elastic Beanstalk ожидает иное поведение.

Решение: Используйте конфигурацию .ebextensions для правильной настройки службы и убедитесь, что сопоставление портов в Dockerrun.aws.json соответствует порту Daphne.

Проблема 4: Статические файлы не обслуживаются

Проблема: Статические файлы не обслуживаются правильно через прокси.

Решение: Настройте NGINX для прямого обслуживания статических файлов:

nginx
location /static/ {
    alias /static/;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Лучшие практики

  1. Используйте Supervisor: Используйте Supervisor для управления процессами Daphne, как показано в результатах исследований источник.

  2. Правильные переменные окружения: Настройте переменные окружения Django в конфигурации EB.

  3. Логирование: Настройте правильное логирование как для Django, так и для Daphne для устранения проблем.

  4. Масштабирование: Используйте Redis для слоев каналов при масштабировании на нескольких экземплярах источник.

  5. Проверки работоспособности: Реализуйте правильные конечные точки проверки работоспособности, которые может использовать Elastic Beanstalk.

  6. Маршрутизация WebSocket: Используйте балансировщики нагрузки приложений (ALB) с поддержкой WebSocket для лучшей маршрутизации источник.

  7. Оптимизация контейнеров: Используйте многоэтапные сборки в Docker для создания более мелких и безопасных контейнеров.

Следуя этим конфигурациям и лучшим практикам, вы должны успешно развернуть Django с Channels, ASGI и Daphne на AWS Elastic Beanstalk с использованием Docker. Ключевым является обеспечение правильного проксирования как HTTP, так и WebSocket-трафика NGINX Elastic Beanstalk на ваш сервер Daphne, работающий внутри контейнера.

Источники

  1. How to deploy django channels 2.x on AWS Elastic Beanstalk? - Stack Overflow
  2. How to Deploy Django Channels 2.x on AWS Elastic Beanstalk | Medium
  3. Stuck with django asgi server (dpahne) and aws eb (with docker) - Stack Overflow
  4. Django Channels on AWS Elastic Beanstalk using an ALB · GitHub
  5. Issues with django-channels deployment on elastic-beanstalk - Stack Overflow
  6. Deploy Django Channels + Websockets on AWS Elastic Beanstalk using Gunicorn, Supervisor & Redis Elasticache | Medium
  7. How to deploy Django Channels 2.x on AWS Elasticbeanstalk using Amazon Linux 2 AMI | Xoxzo Official Blog

Заключение

Развертывание Django с Channels + ASGI + Daphne на AWS Elastic Beanstalk с использованием Docker требует тщательной настройки нескольких компонентов:

  • Настройка Docker: Правильный Dockerfile и скрипт entrypoint для запуска Daphne
  • Параметры Elastic Beanstalk: Конфигурации EB для управления Daphne как службой
  • ASGI-приложение: Правильная настройка ASGI для Channels
  • Прокси-сервер NGINX: Правильная конфигурация проксирования как для HTTP, так и для WebSocket-трафика

Следуя предоставленному полному рабочему примеру, вы должны решить проблему маршрутизации трафика и получить полностью функциональное приложение Django Channels, работающее на Elastic Beanstalk. Не забудьте тщательно протестировать как HTTP, так и WebSocket-подключения после развертывания и следить за логами на предмет возможных проблем, которые могут возникнуть во время выполнения.

Авторы
Проверено модерацией
Модерация