Django Channels 2.4 和 Websockets 在 Elastic Beanstalk 和 ElastiCache 上给出 502 错误
Posted
技术标签:
【中文标题】Django Channels 2.4 和 Websockets 在 Elastic Beanstalk 和 ElastiCache 上给出 502 错误【英文标题】:Django Channels 2.4 and Websockets giving 502 error on Elastic Beanstalk and ElastiCache 【发布时间】: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 tutorial 和 this 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 的出站规则。
【问题讨论】:
【参考方案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。查看编辑后的答案(除非您这样做并且令人困惑)。以上是关于Django Channels 2.4 和 Websockets 在 Elastic Beanstalk 和 ElastiCache 上给出 502 错误的主要内容,如果未能解决你的问题,请参考以下文章
如何处理高传入数据并将受限制的数据发送到 django-channels 中的 Web 套接字
带有 3rd 方数据库的 Django Channels 和 Web Socket
如何在 Heroku 上使用 Channels 和 Celery 部署 Django?
Django Channels - 根据打开的 Web 套接字的数量多次调用接收器函数