【问题标题】:Django and Elastic Beanstalk URL health checksDjango 和 Elastic Beanstalk URL 运行状况检查
【发布时间】:2016-06-14 01:19:31
【问题描述】:

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

我想指定一个health check 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 不要关心 ALLOWED_HOSTS 的某些特定路径(即健康检查 URL)
  • 做一些时髦的事情,比如在启动时调用 EC2 信息 API 来获取主机的 FQDN 并将其附加到 ALLOWED_HOSTS

这些似乎都不是特别令人愉快。谁能推荐一个更好/现有的解决方案?

(为免生疑问,我认为这个问题与“禁用ALLOWED_HOSTS,在主机上过滤的前端HTTPD”的情况相同 - 我希望健康检查命中Django ,而不是前端 HTTPD)

【问题讨论】:

  • @TheGeorgeous 很抱歉没有早点说清楚——这正是我所追求的;想将其发布为答案以便我接受吗? (希望你不介意,如果我在一个月内没有收到你的消息,我会这样做,这样任何登陆这里的人都会更清楚地看到它!)

标签: django amazon-web-services amazon-elastic-beanstalk


【解决方案1】:

如果 ELB 运行状况检查使用包含弹性 beanstalk 域(*.elasticbeanstalk.com,或 EC2 域 *.amazonaws.com)的主机标头发送其请求,则标准 ALLOWED_HOSTS 仍可与'.amazonaws.com''.elasticbeanstalk.com' 的通配符条目。

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

您可以使用 Apache 来处理已批准的主机,而不是向 Django 传播不明确的请求。由于主机标头旨在成为接收请求的服务器的主机名,因此此解决方案将有效请求的标头更改为使用预期的站点主机名。使用弹性beantalk,您需要使用.ebextensions 配置Apache,如here 所述。在项目根目录下的.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/ 替换为您的健康检查网址,将example.com 替换为您网站的相应域。这告诉 Apache 检查所有传入的请求,并使用请求适当的健康检查 URL 的适当的健康检查用户代理更改请求的主机头。

如果您真的不想配置 Apache,您可以编写一个自定义中间件来验证健康检查。中间件必须覆盖 Django 的 CommonMiddleware,它调用 HttpRequestget_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)

这只允许任何健康检查请求跳过主机验证。然后,您将在 settings.py 中将 django.middleware.common.CommonMiddleware 替换为 path.CommonOverrideMiddleware

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

【讨论】:

  • 在尝试了几种策略之后,Apache 方法是唯一对我有用的方法。
  • 关于 apache 的好建议。另外我想说的是,此时的用户代理字符串是“ELB-HealthChecker/2.0”。实施此方法的人员应检查 /var/log/httpd/access_log 以获取最新的用户代理字符串。
【解决方案2】:

这是我用的,效果很好:

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

您将mydomainmydomain.elasticbeanstalk.com 替换为您自己的。

【讨论】:

猜你喜欢
  • 2015-11-16
  • 2018-11-07
  • 2020-11-10
  • 2018-11-02
  • 1970-01-01
  • 2012-07-13
  • 2020-03-14
  • 2021-01-16
  • 1970-01-01
相关资源
最近更新 更多