amazon-web-services - 如何使用 AWS、Docker、Nginx + Daphne 在生产中正确配置 Django Channels?

标签 amazon-web-services docker nginx django-channels daphne

我们正在尝试通过使用 Django Channels 2、AWS 和 Nginx + Daphne 在我们的网站上配置实时聊天。我们的设置在本地运行良好,但是我们在部署到生产时遇到了问题。
我们的生产环境由两个使用 Elastic Container Service (Fargate) 部署到 AWS 的 Docker 容器组成。前面运行的容器是一个nginx配置,它充当代理服务器来服务静态文件。第二个容器运行我们的 API/Django 站点。代理在端口 8000 上运行,并将传入请求转发到 API/Django 容器,该容器在端口 9000 上运行。我还将注意到我们正在使用 terraform 来配置我们的 AWS 环境。
我引用了多篇完成类似设置的文章。例如:
https://medium.com/@elspanishgeek/how-to-deploy-django-channels-2-x-on-aws-elastic-beanstalk-8621771d4ff0
但是,此设置使用了我们未使用的 Elastic Beanstalk 部署。
Image of setup example
代理Dockerfile:

FROM nginxinc/nginx-unprivileged:1-alpine
LABEL maintainer='CodeDank'

COPY ./default.conf.tpl /etc/nginx/default.conf.tpl
COPY ./uwsgi_params /etc/nginx/uwsgi_params

ENV LISTEN_PORT=8000
ENV APP_HOST=app
ENV APP_PORT=9000

USER root

RUN mkdir -p /vol/static
RUN chmod 755 /vol/static
RUN touch /etc/nginx/conf.d/default.conf
RUN chown nginx:nginx /etc/nginx/conf.d/default.conf

COPY ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

USER nginx

CMD ["/entrypoint.sh"]
API/站点 Dockerfile:
FROM python:3.7-alpine3.11
LABEL maintainer="CodeDank"

ENV PYTHONUNBUFFERED 1
ENV PATH="/scripts:${PATH}"

RUN pip install --upgrade pip

COPY ./requirements.txt /requirements.txt
RUN apk add --update --no-cache postgresql-client jpeg-dev
RUN apk add --update --no-cache --virtual .tmp-build-deps \
        gcc libc-dev linux-headers postgresql-dev \
        musl-dev zlib zlib-dev
RUN apk add --update --no-cache libressl-dev musl-dev libffi-dev
RUN apk add --update --no-cache g++ freetype-dev jpeg-dev
RUN pip install -r /requirements.txt
RUN apk del .tmp-build-deps

RUN mkdir /app
WORKDIR /app
COPY ./app /app
COPY ./scripts /scripts
RUN chmod +x /scripts/*

RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
RUN adduser -D user
RUN chown -R user:user /vol/
RUN chmod -R 755 /vol/web
USER user

CMD ["entrypoint.sh"]
(入口点脚本如下所示)
我们创建了一个 AWS Elasticache Redis 服务器,用作 Django channel 的 CHANNEL_LAYERS 后端。 'REDIS_HOSTNAME' 环境变量是 redis 服务器的端点地址。
# Channels Settings
ASGI_APPLICATION = "app.routing.application"
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [
                (os.environ.get('REDIS_HOSTNAME'), 6379)
            ],
        },
    },
}
asgi.py 文件:
import os
import django
from channels.routing import get_default_application


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings')
django.setup()
application = get_default_application()
按照 Channels 文档,我们尝试配置 daphne 以在我们的项目中运行 asgi 应用程序。理想情况下,我们希望此设置让我们的 nginx 代理服务器将所有 websocket 请求转发到运行在端口 9001 上的 daphne 服务器。我们所有的 websocket 端点都将包含/ws/,因此 nginx 代理配置已定义如下所示。
默认.conf.tpl:
upstream channels-backend {
 server localhost:9001;
}

server {
    listen ${LISTEN_PORT};

    location /static {
        alias /vol/static;
    }

    location / {
        uwsgi_pass              ${APP_HOST}:${APP_PORT};
        include                 /etc/nginx/uwsgi_params;
        client_max_body_size    4G;
    }

    location /ws/ {

         proxy_pass http://channels-backend;
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";
         proxy_redirect off;
         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-Host $server_name;
    }
}
代理入口点脚本:
#!/bin/sh

set -e

envsubst '${LISTEN_PORT},${APP_HOST},${APP_PORT}' < /etc/nginx/default.conf.tpl > /etc/nginx/conf.d/default.conf
nginx -g 'daemon off;'
API/站点入口点脚本:
#!/bin/sh

set -e

python manage.py collectstatic --noinput
python manage.py wait_for_db
python manage.py migrate

uwsgi --socket :9000 --workers 4 --master --enable-threads --module app.wsgi

daphne -b 0.0.0.0 -p 9001 app.asgi:application
尝试连接到我们网站上的 websocket 时,会返回 502 错误。
Error during WebSocket handshake: Unexpected response code: 502.
我怀疑 daphne 服务器没有像我们预期的那样运行,或者它没有正确配置 nginx 服务器。在 API 入口点脚本中,daphne 命令是否会按照目前的方式运行?或者,我们是否缺少让 daphne 在 nginx 代理后面运行所需的任何内容?我最初的想法是在入口点脚本中的 uwsgi 命令之后无法运行 daphne 命令。但是,我不确定该命令还需要放置在哪里才能运行 daphne 进程。
代理的 cloudwatch 日志不是非常详细,但是当我尝试连接到站点上的 websocket 时收到此错误消息。
[error] 8#8: *53700 connect() failed (111: Connection refused) while connecting to upstream, client: 10.1.1.190, server: , request: "GET /ws/chat/djagno/ HTTP/1.1", upstream: "http://127.0.0.1:9001/ws/chat/djagno/", host: "mycustomdomain.net"
我已经看到有其他方法可以解决这个问题,不包括使用 Nginx 代理将 websocket 流量定向到 daphne。也许我们的方法不是最好的解决方案?我们对替代配置持开放态度。
任何反馈将不胜感激。谢谢!

最佳答案

我想到的一件事是,您是否正在扩展 nginx 容器?您可能需要在应用程序负载均衡器上启用 session 粘性才能使 websockets 工作。
引用:
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#sticky-sessions

关于amazon-web-services - 如何使用 AWS、Docker、Nginx + Daphne 在生产中正确配置 Django Channels?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64342560/

相关文章:

amazon-web-services - AWS S3 - ACL 与 CORS 配置与存储桶/对象权限

ubuntu - 如何从我克隆的 github 存储库中获取 "run"dockerfile?

php - fatal error :未捕获错误:调用未定义函数mysqli_connect()

docker - 更新 docker 镜像的正确方法是什么

nginx - plesk 上的 Varnish + Nginx 代理配置

java - 通过url动态存储和访问文件

amazon-web-services - 客户端打算发送太大的正文 EB Nginx

java - DynamoDB 条件 ttl

php - nginx fpm gzip压缩不起作用

ssl - 登录 artifactory docker registry 时出现隧道连接失败错误