GitLab CI流水线中Docker容器内Django无法获取ALLOWED_HOSTS环境变量
你踩了一个Docker+CI环境变量隔离的常见坑——GitLab CI Job里的环境变量并不会自动传递给docker run启动的容器,这就是为什么你在Job里echo $DJANGO_ALLOWED_HOSTS能看到值,但容器内的Django却拿不到的原因。至于SECRET_KEY能正常工作,大概率是你的Dockerfile里给它设置了默认ENV值,或者镜像构建时不小心把它打包进去了,但ALLOWED_HOSTS没有这个兜底,所以才会报NoneType的错误。
下面给你几个直接可行的解决办法:
方法1:用docker run的-e参数显式传递变量
这是最直接的方式,在docker run命令里通过-e把需要的变量逐个传递给容器:
docker run --rm \ -e SECRET_KEY="$SECRET_KEY" \ -e DJANGO_ALLOWED_HOSTS="$DJANGO_ALLOWED_HOSTS" \ $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project
这样容器内部就能直接读取到这两个环境变量,Django的配置也能正常执行split()操作了。
方法2:用环境变量文件批量传递(适合变量较多的场景)
如果你的项目需要传递很多环境变量,可以先把CI里的变量写入一个临时的.env文件,再通过--env-file参数加载:
# 在CI Job中生成临时环境变量文件 echo "SECRET_KEY=$SECRET_KEY" > .env-ci echo "DJANGO_ALLOWED_HOSTS=$DJANGO_ALLOWED_HOSTS" >> .env-ci # 运行容器时加载这个文件 docker run --rm --env-file .env-ci $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA py.test ./my_project
方法3:给Dockerfile添加默认环境变量(可选兜底方案)
如果你想给开发/CI环境设置一个默认的ALLOWED_HOSTS值,可以在Dockerfile里添加:
ENV DJANGO_ALLOWED_HOSTS="localhost 127.0.0.1 [::1]"
这样即使忘记传递变量,Django也能拿到一个默认值避免报错,但这个方法不如动态传递灵活,建议只作为兜底手段。
关键原理补充
GitLab CI的Runner本身是运行在一个容器里的,你设置的variables是属于这个Runner容器的环境变量;而docker run启动的是另一个完全独立的容器,两者的环境是隔离的——Docker不会自动把宿主机(这里就是Runner容器)的环境变量注入到新容器里,必须通过-e或--env-file显式指定。
修改完docker run命令后,再运行CI流水线应该就能解决这个报错了。
内容的提问来源于stack exchange,提问作者Bravo2bad

