Django 和 Elastic Beanstalk URL 运行状况检查

问题描述 投票:0回答:3

我有一个 Django 网络应用程序。它在 Elastic Beanstalk 上的 Docker 内部运行。

我想指定一个 健康检查 URL 来进行比“ELB 能否建立 TCP 连接”更高级的健康检查。

完全合理的是,ELB 通过 HTTP 连接到实例,使用实例的主机名(例如

ec2-127-0-0-1.compute-1.amazonaws.com
)作为
Host
标头来实现此目的。

Django 有

ALLOWED_HOSTS
,它可以验证传入请求的
Host
标头。我通过环境变量将其设置为我的应用程序的外部域。

毫不奇怪且完全合理的是,由于缺乏匹配,Django 拒绝了 ELB URL 健康检查

Host

我们不想禁用

ALLOWED_HOSTS
,因为我们希望能够信任
get_host()

到目前为止的解决方案似乎是:

  • 以某种方式说服 Django 不关心某些特定路径(即健康检查 URL)
    ALLOWED_HOSTS
  • 执行一些有趣的操作,例如在启动时调用 EC2 信息 API 以获取主机的 FQDN 并将其附加到
  • ALLOWED_HOSTS
    
    
这些看起来都不是特别令人愉快。谁能推荐一个更好/现有的解决方案?

(为了避免疑问,我相信这个问题与“禁用

ALLOWED_HOSTS

,前端HTTPD在主机上过滤”的情况相同 - 我希望健康检查命中
Django,而不是前端HTTPD)

django amazon-web-services amazon-elastic-beanstalk
3个回答
12
投票
如果 ELB 运行状况检查发送的请求带有包含 Elastic beanstalk 域(*.elasticbeanstalk.com 或 EC2 域 *.amazonaws.com)的主机标头,则标准

ALLOWED_HOSTS

 仍然可以与通配符条目一起使用
'.amazonaws.com'
'.elasticbeanstalk.com'

就我而言,我收到了标准 ipv4 地址作为运行状况检查主机,因此需要不同的解决方案。如果您根本无法预测主机,并且假设您无法预测可能会更安全,那么您将需要采取如下路线之一。

您可以使用 Apache 处理批准的主机,而不是向 Django 传播不明确的请求。由于主机标头旨在作为接收请求的服务器的主机名,因此此解决方案更改有效请求的标头以使用预期的站点主机名。使用 Elastic beanstalk,您需要使用

.ebextensions

 配置 Apache,如
此处所述。在项目根目录中的 .ebextensions
 目录下,将以下内容添加到 .config 文件中。

files: "/etc/httpd/conf.d/eb_healthcheck.conf": mode: "000644" owner: root group: root content: | <If "req('User-Agent') == 'ELB-HealthChecker/1.0' && %{REQUEST_URI} == '/status/'"> RequestHeader set Host "example.com" </If>

/status/

 替换为您的健康检查 URL,并将 
example.com
 替换为您网站的相应域。这告诉 Apache 检查所有传入请求,并使用请求适当健康检查 URL 的适当健康检查用户代理更改请求的主机标头。

如果您确实不想配置 Apache,您可以编写自定义中间件来验证运行状况检查。中间件必须重写 Django 的

CommonMiddleware

,它调用 HttpRequest
get_host()
 方法来验证请求的主机。你可以做这样的事情

from django.middleware.common import CommonMiddleware class CommonOverrideMiddleware(CommonMiddleware): def process_request(self, request): if not('HTTP_USER_AGENT' in request.META and request.META['HTTP_USER_AGENT'] == 'ELB-HealthChecker/1.0' and request.get_full_path() == '/status/'): return super().process_request(request)

这仅允许任何健康检查请求跳过主机验证。然后,您可以将

django.middleware.common.CommonMiddleware

 中的 
path.CommonOverrideMiddleware
 替换为 
settings.py

我建议使用 Apache 配置方法来避免中间件中的任何细节,并将 Django 与主机问题完全隔离。


4
投票
我用的就是这个,效果很好:

import socket local_ip = str(socket.gethostbyname(socket.gethostname())) ALLOWED_HOSTS=[local_ip, '.mydomain.com', 'mydomain.elasticbeanstalk.com' ]

您可以将

mydomain

mydomain.elasticbeanstalk.com
 替换为您自己的。


0
投票
对于 2024 年左右遇到此问题的任何人,AWS 将其默认代理服务器更改为 Nginx 并使用

.platform

 目录来设置自定义服务器配置。对我有用的解决方案:

创建一个类似

.platform/nginx/conf.d/elasticbeanstalk/healthcheck.conf

 的文件:

location /health-check/ { proxy_set_header Host api.example.com; proxy_pass http://localhost:8000; # whatever your application port is }
    
© www.soinside.com 2019 - 2024. All rights reserved.