Docker 环境变量传递进阶:优先级、覆盖与排错
Docker 环境变量的优先级:docker run -e > compose environment > env_file > Dockerfile ENV;ARG 只存在于构建期。本文讲清覆盖关系、ARG 与 ENV 的分工及变量"不生效"的排查。
核心规则:同一个变量,运行期注入覆盖构建期设定——docker run -e 优先级最高,其次是 compose 的 environment:,再是 env_file:,最低是 Dockerfile 的 ENV。ARG 则完全不同:只在构建期存在,运行期容器里根本看不到。
优先级一览(高→低)
# Dockerfile
ENV MODE=image-default
# compose
services:
app:
env_file: .env # 优先级 3
environment:
- MODE=compose-value # 优先级 2,覆盖 env_file
docker run -e MODE=runtime-value ... # 优先级 1,最高
ARG vs ENV 分工
ARG VERSION=latest # 构建期参数,docker build --build-arg VERSION=1.2
FROM base:$VERSION
ENV APP_VERSION=$VERSION # 想在容器里也能看到,显式转存 ENV
ARG:构建期有效,docker history可见(别放密码),容器运行期不存在ENV:构建期与运行期都有效,除非被 -e 覆盖
变量"不生效"排查顺序
# 1. 容器里实际的值
docker exec myapp printenv MY_VAR
# 2. 创建时注入的值
docker inspect myapp --format '{{.Config.Env}}'
# 3. compose 渲染后的最终配置
docker compose config | grep -A5 environment
三层对照:inspect 有而容器内没有 → 应用/entrypoint 覆盖了;inspect 就没有 → 注入环节没写对;compose 渲染结果与预期不符 → yml 里变量替换(${})与环境注入混淆。
compose 里两个 .env 的坑
docker compose自动读项目根的.env——用于yml 里的 ${VAR} 替换- 要注入容器内,必须
env_file:显式声明
两个用途同名不同命,混用是最高频错误。
敏感变量的正确姿势
环境变量可被 docker inspect 读出,生产秘钥建议:秘钥文件挂载、编排层 Secret(K8s Secret/Swarm secret)、或启动时从密管系统拉取。
观测云对照
配置差异引发的问题按标签定位。 观测云的日志与指标按环境、版本标签分组,"同镜像不同环境变量导致行为分叉"类问题,对照两组标签的数据即可锁定差异变量。
常见问题(FAQ)
Q:改了 .env 文件容器内怎么没变?
A:环境变量是创建期注入的,改文件后要 docker compose up -d 重建容器。
Q:数组型变量怎么传(如多个 host)?
A:环境变量只能是字符串,约定分隔符(逗号)由应用解析,或改用配置文件挂载。
Q:能在 ENTRYPOINT 里动态计算变量吗?
A:可以,entrypoint 脚本里 export 的变量对随后启动的主进程生效——这是运行期动态配置的常见模式。