扩展the answer provided by dfrdmn:
虽然这个答案在大多数情况下效果很好,但它有几个潜在的小问题。
AWS ELB 网络负载均衡器
首先,如果您使用的是 ELB 网络 负载均衡器,此方法将无法使用其 HTTP 健康检查,因为负载均衡器会发送 负载均衡器的 IP 地址 em> 在 HTTP 主机标头中。来自the AWS docs:
健康检查请求中的HTTP主机头包含负载均衡节点的IP地址和监听端口,而不是目标的IP地址和健康检查端口。如果您按主机标头映射传入请求,则必须确保运行状况检查与任何 HTTP 主机标头匹配。另一种选择是在不同的端口上添加单独的 HTTP 服务,并将目标组配置为使用该端口进行健康检查。或者,考虑使用 TCP 健康检查。
因此,将您的实例(目标组)IP 添加到您的ALLOWED_HOSTS 将不起作用。如前所述,您可以使用 TCP 健康检查,也可以使用另一个答案中描述的中间件方法。
元数据端点被限制
其次,由于元数据端点限制并发连接数和throttles请求数,在某些情况下您可能会遇到问题。
您的 Django settings.py 文件为每个 进程执行,并且任何时候进程都需要重新启动。如果您的网络服务器配置为使用多个进程(例如使用 gunicorn workers 时),这一点很重要,因为通常配置为正确充分利用系统 CPU 资源。
这意味着,如果有足够的进程,您的settings.py 文件将被执行多次,向元数据端点发送许多并发请求,您的进程可能无法启动。此外,在后续进程重新启动时,节流将加剧节流问题。在某些情况下,这可能会导致您的应用程序停止运行或运行的进程少于预期。
要解决这个问题,您可以做一些事情:
-
在启动服务器之前获取 IP 地址并将 IP 地址设置为环境变量,然后读取环境变量以将其添加到允许的主机中。
$ export ALLOWED_HOST_EC2_PRIVATE_IP=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)
$ gunicorn -w 10 ... myapp:app
# settings.py
ALLOWED_HOSTS = ['myhost.tld', ]
if os.getenv('ALLOWED_HOST_EC2_PRIVATE_IP'):
ALLOWED_HOSTS.append(os.environ['ALLOWED_HOST_EC2_PRIVATE_IP'])
如果许多应用程序或其他服务同时使用实例的元数据,您可能仍会遇到元数据端点的限制问题。
- 对于在 ECS 上的容器中运行的服务,您可以使用 container metadata file
您可以在settings.py 中安全地执行此操作,因为访问此文件没有限制或速率限制。这也避免了您的应用程序可能干扰需要实例元数据端点的其他服务。
# settings.py
import os
import json
ALLOWED_HOSTS = ['myhost.tld', ]
if os.getenv('ECS_CONTAINER_METADATA_FILE'):
metadata_file_path = os.environ['ECS_CONTAINER_METADATA_FILE']
with open(metadata_file_path) as f:
metadata = json.load(f)
private_ip = metadata["HostPrivateIPv4Address"]
ALLOWED_HOSTS.append(private_ip)
您还可以在容器的 ENTRYPOINT 中将第一种方法与元数据文件结合起来。
#!/usr/bin/env bash
# docker-entrypoint.sh
export ALLOWED_HOST_EC2_PRIVATE_IP=$(jq -r .HostPrivateIPv4Address $ECS_CONTAINER_METADATA_FILE)
exec "$@"
FROM myapplication
COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["gunicorn", "whatever"]