ENV 与 export 的区别
两者看起来都在设置变量,但生命周期完全不同。RUN 里写 export 设置的是那一条命令所在 shell 会话的变量,命令结束就消失,下一条 RUN 是新进程,读不到;ENV 写入镜像配置,后续所有构建步骤与容器运行时都能读到。搞混这两者,是「构建脚本里明明设置了,下一条指令却读到空值」这类问题的根因。
基本信息
| RUN export | 仅当前 shell 会话有效,随命令结束消失 |
|---|---|
| ENV | 写入镜像配置,构建后续步骤与运行时均生效 |
| 查看方式 | docker image inspect -f '{{json .Config.Env}}' 镜像 |
| ARG 对比 | ARG 只在构建期可用,不进镜像配置 |
| 运行时覆盖 | docker run -e KEY=值 覆盖镜像内 ENV |
| 多阶段影响 | ENV 只在声明的阶段内生效,跨阶段需显式传递 |
典型使用场景
- 构建期临时变量(版本号、下载地址)用 shell 变量即可,不必写进镜像
- 应用默认配置(时区、语言、运行环境名)用 ENV,让运行时自动可用
- 排查容器读不到变量:先看镜像配置里有没有这个键
- 区分构建参数与运行时配置:构建参数不应残留在最终镜像里
- 多阶段构建中把上游阶段的路径或版本传递给下游阶段
三种写法的差别
三种写法的差别
# 一、shell 变量:只在本次 RUN 内有效
RUN export FOO=bar && echo "$FOO" # 能打印 bar
RUN echo "$FOO" # 打印空值,变量已随上条命令消失
# 二、ENV:写入镜像配置,后续步骤与运行时都能读到
ENV APP_ENV=production \
TZ=Asia/Shanghai
RUN echo "$APP_ENV" # 能读到
# 三、ARG:只在构建期使用,不进入镜像配置
ARG APP_VERSION=dev
RUN echo "building ${APP_VERSION}" # 能读到,但运行容器时不存在这个变量核对与覆盖
核对与覆盖
# 查看镜像内置的环境变量
docker image inspect -f '{{json .Config.Env}}' app/web:1.0
# 运行时覆盖(仅本次容器生效)
docker run -d -e APP_ENV=staging --name api app/web:1.0
# 确认容器内实际取值
docker exec api env | grep -E 'APP_ENV|TZ'
# 多阶段构建中把变量显式传给下游阶段
# FROM build AS builder ... ENV OUT=/out
# FROM runtime ... COPY --from=builder $OUT/app /app变量类型对照
| 写法 | 构建期可见 | 运行期可见 | 写入镜像配置 |
|---|---|---|---|
| RUN export | 仅本条命令 | 不可见 | 否 |
| ENV | 后续步骤 | 可见 | 是 |
| ARG | 本阶段内 | 不可见 | 否 |
| docker run -e | 无关 | 仅该容器 | 否 |
| 基础镜像 ENV | 后续步骤 | 可见 | 是(继承) |
构建阶段用 ENV 设置的变量会留在最终镜像里,多余的调试变量可能影响应用的配置优先级,交付前应清理只用于构建的项。
需要变量展开与默认值时,shell 形式或显式套一层 shell 都可以;exec 形式(JSON 数组)不展开变量,参数会原样传入。