如何解决 AWS Elastic Beanstalk Django 运行状况检查问题

Posted

技术标签:

【中文标题】如何解决 AWS Elastic Beanstalk Django 运行状况检查问题【英文标题】:How to resolve AWS Elastic Beanstalk Django health check problems 【发布时间】:2020-11-10 15:18:22 【问题描述】:

我最近将我的 Django API 后端部署到 AWS EB 到他们的 Linux 2 系统(确切的平台名称是 Python 3.7 running on 64bit Amazon Linux 2)。

几乎一切都按预期工作,但我的应用程序运行状况为 Severe,经过数小时的调试后,我不知道为什么。

正在使用以下端点(django-health-check 模块)处理应用程序的运行状况检查。

url(r'^ht/', include('health_check.urls'))

100% 的请求的状态代码为 200,但我的整体健康状况如下:

|--------------------|----------------|---------------------------------------------------|
|   instance-id      |   status       |   cause                                           |
|--------------------|----------------|---------------------------------------------------|
|   Overall          |   Degraded     |   Impaired services on all instances.             |
|   i-0eb89f...      |   Severe       |   Following services are not running: release.    |
|--------------------|----------------|---------------------------------------------------|

最奇怪的是Following services are not running: release.的消息是互联网独有的(似乎以前没有人遇到过这样的问题)。

另一个奇怪的事情是我的/var/log/healthd/daemon.log 文件的内容类似于

W, [2020-07-21T09:00:01.209091 #3467]  WARN -- : log file "/var/log/nginx/healthd/application.log.2020-07-21-09" does not exist

时间变化的地方。

最后可能相关的是我在.ebextensions 目录中的单个文件的内容:

option_settings:
  "aws:elasticbeanstalk:application:environment":
    DJANGO_SETTINGS_MODULE: "app.settings"
    "PYTHONPATH": "/var/app/current:$PYTHONPATH"
  "aws:elasticbeanstalk:container:python":
    WSGIPath: app.wsgi:application
    NumProcesses: 3
    NumThreads: 20
  aws:elasticbeanstalk:environment:proxy:staticfiles:
    /static: static
    /static_files: static_files
container_commands:
  01_migrate:
    command: "source /var/app/venv/staging-LQM1lest/bin/activate && python manage.py migrate --noinput"
    leader_only: true
packages:
  yum:
    git: []
    postgresql-devel: []

有谁知道如何解决这个问题?最终目标是拥有绿色OK健康。


编辑:最后我切换到Basic 卫生系统,问题突然消失了。不过,我仍然有兴趣解决最初的问题,因为 Enhanced 卫生系统提供了一些好处

【问题讨论】:

是负载均衡的环境吗? @Marcin 是的,我也忘了提到我正在使用Enhanced health reporting and monitoring 应用程序是否完全按预期工作? /var/log/cloud-init-cmd 等日志不显示错误? @Marcin 我的意思是端点和数据库都工作得很好。我从 EB 控制台下载了完整的日志并浏览了它们。我发现的只是 eb-engine.log 中的 2 个似乎不相关的错误([ERROR] nginx: the configuration file /var/proxy/staging/nginx/nginx.conf syntax is ok nginx: configuration file /var/proxy/staging/nginx/nginx.conf test is successful[ERROR] Created symlink from /etc/systemd/system/multi-user.target.wants/worker.service to /etc/systemd/system/worker.service.)。一个名为 cloud-init-cmd 的文件甚至不是日志的一部分。 @Marcin 我也切换到Basic 卫生系统(而不是Enhanced),问题就消失了。不过,我仍然有兴趣解决原来的问题。 【参考方案1】:

我认为您遇到的问题可能是由于文件 settings.py 中的 ALLOWED_HOSTS 设置造成的。

EB 向您的应用程序发送一个 HTTP 请求以查看其是否正常工作,但 Django 会阻止任何不是来自设置变量中指定主机的通信。但是这里有一个问题,EB将请求发送到ec2实例的私有ip。

解决此问题的最简单方法是在您的settings.py 文件中允许所有这样的主机:

ALLOWED_HOSTS=['*']

这可能会导致安全问题,但这是最快的方法。现在,为了使其动态工作,因为 ec2 实例可以随时启动,私有 ip 从一个实例更改为另一个实例。

要解决这个问题,您必须在部署过程开始时获取私有 IP。

settings.py 的顶部放置以下函数:

import os
import requests
# Other imports ...

def is_ec2_linux():
"""Detect if we are running on an EC2 Linux Instance
   See http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html
"""
    if os.path.isfile("/sys/hypervisor/uuid"):
        with open("/sys/hypervisor/uuid") as f:
            uuid = f.read()
            return uuid.startswith("ec2")
    return False

def get_token():
"""Set the autorization token to live for 6 hours (maximum)"""
    headers = 
        'X-aws-ec2-metadata-token-ttl-seconds': '21600',
    
    response = requests.put('http://169.254.169.254/latest/api/token', headers=headers)
    return response.text


def get_linux_ec2_private_ip():
    """Get the private IP Address of the machine if running on an EC2 linux server.
See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html"""

    if not is_ec2_linux():
        return None
    try:
        token = get_token()
        headers = 
            'X-aws-ec2-metadata-token': f"token",
        
        response = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', headers=headers)
        return response.text
    except:
        return None
    finally:
        if response:
            response.close()
# Other settings

最重要的函数是get_token()get_linux_ec2_private_ip(),第一个设置访问令牌并检索它,以便第二个使用它并获取当前的ec2实例IP。

检索到它后,将其添加到您的 ALLOWED_HOSTS

ALLOWED_HOSTS = ['127.0.0.1', 'mywebsite.com']
private_ip = get_linux_ec2_private_ip()
if private_ip:
   ALLOWED_HOSTS.append(private_ip)

之后,只需提交您的更改并使用 eb deploy 重新部署它(如果您已设置 EB CLI)。

【讨论】:

以上是关于如何解决 AWS Elastic Beanstalk Django 运行状况检查问题的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 AWS Elastic Beanstalk Django 运行状况检查问题

更新 AWS Elastic Beanstalk 解决方案堆栈名称

如何从 aws-sdk 中的 s3 存储桶创建 Elastic Beanstalk 实例?

AWS Elastic beanstalk - 更改解决方案堆栈名称

AWS Elastic Beanstalk - 设置 JVM 选项(堆空间)

AWS API网关指向Elastic:访问密钥PHP