3

When moving over to ECS with awsvpc networking mode, my ALB says all my hosts are unhealthy because checking /status/ yields 400s. I've narrowed it down to the issue being something wrong with ALLOWED_HOSTS.

How do I get my web app to give 200's to the ELB Healthchecker?

wonton
  • 7,568
  • 9
  • 56
  • 93

3 Answers3

11

Another simple solution would be to write a custom MIDDLEWARE which will give the response to ELB before the ALLOWED_HOSTS is checked.

The middleware can be as simple as:

project/app/middleware.py

from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin

class HealthCheckMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.META["PATH_INFO"] == "/ping/":
            return HttpResponse("pong")

settings.py

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'app.middleware.HealthCheckMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    ...
]

Django Middleware reference https://docs.djangoproject.com/en/dev/topics/http/middleware/

Vaibhav Shelke
  • 376
  • 4
  • 6
8

The solution I came up with is to add the LB's address to ALLOWED_HOSTS:

ELB_HEALTHCHECK_HOSTNAMES = [ip for network in 
    requests.get(os.environ['ECS_CONTAINER_METADATA_URI']).json()['Networks']
    for ip in network['IPv4Addresses']]
ALLOWED_HOSTS += ELB_HEALTHCHECK_HOSTNAMES

This will take every IP from every networks attached to your container and add it to your ALLOWED_HOSTS.

Prior to moving over to ECS with awsvpc networking mode, a lot of us are familiar with this line that retrieves the EC2 instance's IP which is used as the hostname by the ELB health checker:

ELB_HEALTHCHECK_HOSTNAME = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', timeout=2).text

This line under ECS with awsvpc networking retrieves the IP of the EC2 instance, not the ENI attached to your container. To retrieve the IP of the ENI, you send a request to the endpoint in the environment variable ${ECS_CONTAINER_METADATA_URI}

This returns useful metadata about the containers, including the IPV4

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v3.html

wonton
  • 7,568
  • 9
  • 56
  • 93
3

You can try this simple method

from socket import gethostname, gethostbyname

# This environment variable is automatically set when ECS runs a task
if os.environ.get("AWS_EXECUTION_ENV"):
    ALLOWED_HOSTS.append(gethostbyname(gethostname()))
Malik Bagwala
  • 2,695
  • 7
  • 23
  • 38