【问题标题】:Django Channels 2.4 and Websockets giving 502 error on Elastic Beanstalk and ElastiCacheDjango Channels 2.4 和 Websockets 在 Elastic Beanstalk 和 ElastiCache 上给出 502 错误
【发布时间】:2020-12-16 20:27:45
【问题描述】:

我已通过 django 频道将聊天组件集成到我的 django web 应用程序中,其方式与文档中的 here 非常相似。我使用 elasticache 来创建我的 redis 实例。我的 settings.py 如下所示:

ASGI_APPLICATION = 'MyApp.routing.application'
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('my-redis-instance.cache.amazonaws.com', 6379)], #This is a placeholder in the question for the cluster's actual endpoint
        },
    },
}

在将我的应用程序部署到弹性 beantalk 时,我尝试关注 this tutorialthis tutorial,但没有成功。我的 django.config 文件目前如下所示:

container_commands:
    01_collectstatic:
        command: "source /opt/python/run/venv/bin/activate && python manage.py collectstatic --noinput"
    02_migrate:
        command: "django-admin.py migrate"
        leader_only: true
    03_load-data:
        command: "python manage.py load_database"
        leader_only: true

option_settings:
    aws:elasticbeanstalk:application:environment:
        DJANGO_SETTINGS_MODULE: MyApp.settings
    aws:elasticbeanstalk:container:python:
        WSGIPath: MyApp/wsgi.py
    "aws:elasticbeanstalk:container:python:staticfiles":
        /static/: "static/"
    aws:elbv2:listener:80:
        DefaultProcess: http
        ListenerEnabled: 'true'
        Protocol: HTTP
        Rules: ws
    aws:elbv2:listenerrule:ws:
        PathPatterns: /ws/*
        Process: websocket
        Priority: 1
    aws:elasticbeanstalk:environment:process:http:
        Port: '80'
        Protocol: HTTP
    aws:elasticbeanstalk:environment:process:websocket:
        Port: '5000'
        Protocol: HTTP

我还尝试创建一个 Procfile 来配置 gunicorn 和 daphne。它看起来像这样:

web: gunicorn --bind :8000 --workers 3 --threads 2 MyApp.wsgi:application
websocket: daphne -b 0.0.0.0 -p 5000 MyApp.asgi:application

附加到我的 ElastiCache redis 实例的安全组有一个入站规则,其中自定义 TCP 设置为端口 6379,源设置为任何。在尝试所有这些不同的部署方法时,我不断收到以下错误:

[Error] WebSocket connection to 'ws://my-site-url.com/ws/messages/' failed: Unexpected response code: 502

我不知道该怎么做。我看过几个与此相关的堆栈溢出帖子,但没有一个有帮助。这个post 似乎有一个有效的解决方案,但我相信它现在已经过时了。

更新:

在进行更多搜索时,我在我的 .ebextensions 文件夹中创建了一个 websockets-python.config 文件,该文件应该配置 Apache 代理服务器以允许使用 Web 套接字。我还删除了配置 Daphne 和 Gunicorn 的 Procfile。 websockets-python.config 文件如下所示:


files:
  "/etc/httpd/conf.d/proxy-pass.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      ProxyPass /ws/ ws://127.0.0.1:5000/
      ProxyPassReverse /ws/ ws://127.0.0.1:5000/

  "/etc/httpd/conf.modules.d/99-mod_proxy_wstunnel.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      <IfModule !proxy_wstunnel_module>
      LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
      </IfModule>

使用此文件重新部署后,我在 Web 套接字上收到无效状态错误,然后 Web 套接字连接最终超时。我相信网络套接字正在尝试连接,但由于某种原因无法连接(可能是我的安全组的配置方式),然后最终超时。

安全组配置:

ELB:从端口 80 上的任何地方的入站规则。从端口 80 和 5000 到任何地方的出站规则

我的服务器:ELB 在端口 80 和 5000 上的入站规则。所有流量到任何地方的出站规则。

ElastiCache 实例:来自任何地方的端口 6379 和来自服务器的端口 6439 的入站规则。 All Traffic to Anywhere 的出站规则。

【问题讨论】:

    标签: django websocket amazon-elastic-beanstalk django-channels amazon-elasticache


    【解决方案1】:

    经过几天的工作,我找到了解决方案。我无法使负载均衡器上的端口转发工作,但是我将我的配置为转发到 Nginx 上的端口 5000。

    redis 网址:

    CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels_redis.core.RedisChannelLayer",
            "CONFIG": {
                "hosts": [(REDIS_URL, 6379)],
            },
        },
    }
    

    Nginx 配置:

    .platform/nginx/nginx.conf

    #Elastic Beanstalk Nginx Configuration File
    
    user                    nginx;
    error_log               /var/log/nginx/error.log warn;
    pid                     /var/run/nginx.pid;
    worker_processes        auto;
    worker_rlimit_nofile    32137;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        include       conf.d/*.conf;
    
        map $http_upgrade $connection_upgrade {
            default     "upgrade";
        }
    
        server {
            listen        80 default_server;
            access_log    /var/log/nginx/access.log main;
    
            client_header_timeout 60;
            client_body_timeout   60;
            keepalive_timeout     60;
            gzip                  off;
            gzip_comp_level       4;
            gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    
            # Include the Elastic Beanstalk generated locations
            include conf.d/elasticbeanstalk/*.conf;
            
    
            location /ws {
                proxy_pass          http://127.0.0.1:5000;
                proxy_http_version  1.1;
    
                proxy_set_header    Connection          $connection_upgrade;
                proxy_set_header    Upgrade             $http_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   https;
            }
        }
    
    }
    

    过程文件:

    web: gunicorn --bind 127.0.0.1:8000 --workers=1 --threads=15 project.wsgi:application
    websocket: daphne -b 0.0.0.0 -p 5000 project.asgi:application
    

    关于安全组,在创建redis时,需要在安全组上添加当前EC2实例上使用的安全组的id,在入站的destination字段中。

    【讨论】:

      【解决方案2】:

      ~~使用 ElastiCache 时,您必须使用集群的主端点。您可以转到 ElastiCache 的仪表板,转到 Redis,然后单击下拉菜单。找到主要端点并使用它而不是my-redis-instance.cache.amazonaws.com~~

      编辑,因为端点可能只是正确的:问题可能出在 ElastiCache 上的安全组中。 ElastiCache 集群应该只允许从服务器的 SG 入站(在端口 6439 上),它只允许从 ELB 的安全组(在端口 5000 上?)入站,它只允许从端口 443 和端口 80 从任何地方入站。

      最后,我觉得你配置 Gunicorn 和 Daphne 很奇怪。除了 Daphne 可以运行 ASGI 之外,它们不是一回事吗? (只有使用 Gunicorn 的 Uvicorn 工作者才允许使用 ASGI;您应该只使用 Daphne 而不要启用 Gunicorn)。

      这都是理论上你的 AWS 实例有足够的内存和 CPU;这也可能是个问题。我向开发人员推荐 Sentry(免费),以便您查看。由于一些巧妙的错误,我的很多 502 错误都得到了解决。

      【讨论】:

      • 是的,这就是我正在做的。我将“my-redis-instance.cache.amazonaws.com”作为占位符放在问题中,因为我不希望我的实际 redis 端点成为 Stack Overflow 等网站上的公共信息。
      • 根据我以前的经验,502 错误代码通常是由于配置错误(我第一次没有让我的安全组正确,但你似乎把它关闭了......也许)。我很好奇,你的 ELB 上的安全组是什么?我在 ELB 上有一个 80 和 443 的安全组;对于我的服务器,它只是来自我的 ELB 的入站(您必须选择 ELB 的安全组);对于 ElastiCache,您必须将其设置为服务器的安全组。这可能就是为什么您的 ElastiCache 安全组完全暴露在您的 VPC 之外的原因;附加到服务器 SG 应该可以正常工作。
      • 端口 6439 来自哪里还是只是一个标准?
      • 我认为这可能是我的安全组配置的问题。我刚刚用我的安全组配置更新了这个问题。我现在没有设置 HTTPS,所以我不用担心端口 443。如何将 ElastiCache SG 连接到服务器的 SG?
      • 我明白了。对于您服务器的 SG,您应该将 All Traffic 与 Source Type 设置为您的 ELB 的 SG。查看编辑后的答案(除非您这样做并且令人困惑)。
      猜你喜欢
      • 2022-07-01
      • 2019-07-07
      • 1970-01-01
      • 2015-04-27
      • 2017-08-02
      • 2019-07-03
      • 1970-01-01
      • 2019-04-03
      • 2021-09-16
      相关资源
      最近更新 更多