环境变量注入不生效需按四步排查:第一步确认来源优先级(Shell > docker-compose.yml > .env > Dockerfile);第二步验证.env文件位置、命名及插值正确性;第三步用docker inspect或/proc/1/environ检查容器内真实环境;第四步排除镜像启动脚本或ENTRYPOINT导致的变量丢失。
环境变量注入不生效,不是配置写了就完事,而是得看它“真正在容器进程里有没有被加载”。很多故障表面是应用启动失败、连接不上数据库、端口绑定异常,根子都在环境变量没传进去或被覆盖了。排查关键不是堆命令,而是按顺序确认变量从哪来、到哪去、中途有没有被改掉。
第一步:确认变量来源和优先级是否被覆盖
Docker Compose 中环境变量有明确的优先级顺序,高优先级会直接盖掉低优先级的值。常见覆盖链路如下:
- Shell 中已设置的同名变量(例如 export DB_HOST=127.0.0.1),会覆盖 .env 文件和 environment 字段
- docker-compose.yml 里的 environment 字段优先级高于 .env 文件,也高于 env_file
- 镜像 Dockerfile 中的 ENV 是最低优先级,运行时传入的任何值都会覆盖它
验证方式:进容器执行 printenv | grep DB_HOST,再对比你写的 .env、docker-compose.yml 和启动前的 Shell 环境,看哪个值最终生效。
第二步:检查 .env 文件是否被正确加载
.env 文件必须放在 docker-compose.yml 同级目录,且文件名严格为 .env(不能是 env、.env.local 或带空格)。它只影响 docker-compose.yml 中的变量插值,比如:
services:
web:
environment:
- DATABASE_URL=postgres://${DB_HOST}:${DB_PORT}/app
如果 DB_HOST 在 .env 里没定义,或者拼写错误(如写成 db_host),插值就会变成空字符串,最终生成 DATABASE_URL=postgres://:/app —— 这类错误在 docker-compose config 输出里一眼就能发现。
第三步:验证容器内进程实际收到的环境变量
别只信配置文件,要看真实进程环境。两种可靠方式:
- 用 docker inspect 容器名 | jq '.[0].Config.Env' 查容器启动时记录的环境变量列表(注意:这是镜像构建 + 运行时注入后的快照)
- 进容器后执行 cat /proc/1/environ | tr '\0' '\n'(PID 1 是主进程),这才是应用真正读到的环境——有些框架(如 Node.js 的 process.env)读的就是这个
如果这里没有你要的变量,说明注入环节已经失败;如果有了但应用还是读不到,问题可能出在应用自身(比如用了错误的键名、没重启进程、或被代码逻辑覆盖)。
第四步:排除镜像层和运行时干扰
有些基础镜像(尤其是 Alpine 或精简版)会在启动脚本里重置环境变量,或者应用启动命令(ENTRYPOINT/CMD)用 shell 封装时未正确继承变量。典型表现是:docker exec -it 容器 sh 里能看见变量,但主进程里没有。
解决方法:
- 改用 exec 模式启动:确保 docker-compose.yml 中 entrypoint 不起新 shell,或显式用 ["sh", "-c", "exec your-app"]
- 检查 Dockerfile:避免在 RUN 阶段用 export 设置变量(只对当前构建层有效),改用 ENV;也别在 ENTRYPOINT 脚本末尾 unset 掉关键变量
- 重建容器:修改过 .env 或 docker-compose.yml 后,务必 docker-compose down & up -d,旧容器不会自动更新环境


















