You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kubernetes部署Django遇Disallowed Hosts错误,求LoadBalancer白名单配置方法

解决Kubernetes部署Django时的Disallowed Hosts错误(动态LoadBalancer场景)

我明白你遇到的困扰了——Kubernetes动态生成LoadBalancer后,Django因为没把这个LB的地址加入ALLOWED_HOSTS而报错,而且因为LB是动态创建的,没法提前硬编码进去对吧?下面给你几个实用的解决方案,从测试到生产环境都覆盖到:

先修复一个关键配置问题:Service与Pod的Selector不匹配

先提个必须解决的小问题:你的service.yaml里selector是app: mgmt_reporting,但pod.yaml的label是app: my-pod,这会导致Service找不到对应的Pod,流量根本到不了Django容器。先把这个匹配上:要么把Pod的label改成app: mgmt_reporting,要么把Service的selector改成app: my-pod,这是所有方案生效的前提!


方案1:临时测试用——手动获取LB地址并注入环境变量

如果只是临时验证功能,你可以先拿到LoadBalancer的外部IP或主机名:

# 获取LB的外部IP(如果是IP类型的Ingress)
kubectl get service mgmt-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

# 如果云厂商分配的是域名(比如AWS的ELB域名),用这个命令
kubectl get service mgmt-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

然后修改你的pod.yaml,把这个地址作为环境变量传给Django容器:

apiVersion: v1
kind: Pod
metadata:
  name: test.example.com
  labels:
    app: mgmt_reporting # 这里已改成和Service匹配的label
spec:
  containers:
    - name: my-container
      image: my-image:1.0
      ports:
        - name: my-port
          containerPort: 8000
      env:
        - name: DJANGO_ALLOWED_HOSTS
          value: "test.example.com,xxx.xxx.xxx.xxx" # 把xxx替换成你拿到的LB地址

接着在Django的settings.py里读取这个环境变量:

import os
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")

这个方法简单直接,但缺点是如果LB地址变化(比如重新创建Service),你得手动更新Pod的环境变量,适合临时测试用。

方案2:生产环境推荐——容器启动时自动获取LB地址

这个方法更自动化,适合生产环境。思路是在容器启动时,用脚本自动查询LoadBalancer的地址,然后注入到Django的配置里。

步骤1:编写启动脚本

创建一个start.sh脚本,放在你的Django项目目录中:

#!/bin/sh
set -e

# 优先尝试获取LB的主机名,若不存在则获取IP
LB_HOST=$(kubectl get service mgmt-service -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
if [ -z "$LB_HOST" ]; then
  LB_HOST=$(kubectl get service mgmt-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
fi

# 合并原有允许的主机和LB地址
export DJANGO_ALLOWED_HOSTS="test.example.com,$LB_HOST"

# 启动Django服务(如果用gunicorn就替换成对应的启动命令)
exec python manage.py runserver 0.0.0.0:8000

步骤2:更新Dockerfile

把脚本加入镜像,并设置为容器的启动命令:

# 你的原有Dockerfile内容...
COPY start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]

步骤3:给Pod赋予查询Service的权限

因为脚本里要用kubectl查询Service信息,所以需要给Pod的ServiceAccount绑定对应的权限。创建以下RBAC配置文件(比如rbac.yaml):

apiVersion: v1
kind: ServiceAccount
metadata:
  name: django-lb-reader
  namespace: default # 替换成你的Pod所在的命名空间
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: service-reader
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: django-service-reader-binding
subjects:
- kind: ServiceAccount
  name: django-lb-reader
  namespace: default
roleRef:
  kind: ClusterRole
  name: service-reader
  apiGroup: rbac.authorization.k8s.io

执行kubectl apply -f rbac.yaml创建这些权限资源。

步骤4:更新Pod配置使用ServiceAccount

修改pod.yaml,指定使用刚才创建的ServiceAccount:

apiVersion: v1
kind: Pod
metadata:
  name: test.example.com
  labels:
    app: mgmt_reporting
spec:
  serviceAccountName: django-lb-reader # 新增这一行
  containers:
    - name: my-container
      image: my-image:1.0 # 记得重新构建镜像并推送至镜像仓库
      ports:
        - name: my-port
          containerPort: 8000

这样每次容器启动时,都会自动获取当前LoadBalancer的地址,加入到Django的允许主机列表里,完全不需要手动干预。

方案3:测试环境快速绕过(绝对禁止生产环境使用)

如果是本地测试或者开发环境,你可以暂时放宽Django的主机限制:

# settings.py里修改
ALLOWED_HOSTS = ['*']

但绝对不能在生产环境这么做,这会带来严重的安全风险,可能导致主机头攻击。


内容的提问来源于stack exchange,提问作者Sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:44:32