构建时参数(--build-arg)仅在镜像构建阶段生效,构建完成后即消失;运行时环境变量(ENV/environment)才进入容器运行时,应用可读取。两者不可互换,混淆会导致配置失效或启动失败。

构建时参数(--build-arg)和运行时环境变量(ENV / environment)不是一回事
很多人一看到 Dockerfile 里的 ARG 和 ENV,或者 docker-compose.yml 里的 build.args 和 environment,就默认它们作用相同、可以互换。实际完全不是:前者只在镜像构建阶段存在,构建完就消失;后者才真正进入容器运行时,应用代码能读到。混淆这两者,轻则导致配置没生效,重则构建失败或启动报错。
什么时候该用 --build-arg,而不是 environment
--build-arg 是给 Dockerfile 构建过程用的“临时钥匙”,比如拉私有仓库镜像时传 token、编译时指定版本号、跳过某些测试步骤。它不会留在最终镜像里,也不进容器进程环境。
- 典型场景:CI 流水线中动态注入 Git commit hash 到构建产物中 —— 用
ARG COMMIT_SHA+RUN echo $COMMIT_SHA > /app/version - 不能用于:数据库连接地址、API 密钥等运行时才需要的配置 —— 这些必须走
ENV或environment,否则容器启动后根本拿不到 - 注意:如果
ARG没在Dockerfile中显式声明(ARG MY_ARG),即使命令行传了--build-arg MY_ARG=xxx也无效 - 安全提示:别用
--build-arg传密码 —— 构建日志、历史镜像层都可能残留明文
environment 和 ENV 的生效时机和覆盖优先级
ENV 写在 Dockerfile 里,是镜像的“出厂默认值”;environment 写在 docker-compose.yml 里,或用 docker run -e 传入,是容器启动时的“现场覆盖”。后者永远优先于前者。
- 例如
Dockerfile有ENV DB_HOST=localhost,但docker-compose.yml里写environment: - DB_HOST=mysqldb,容器内读到的就是mysqldb - 多个
environment条目之间没有顺序依赖,但若重复定义(如两个- DB_HOST=...),以最后一个为准 - 如果想让某个变量“只在容器里有,镜像里不存”,就别写
ENV,只靠environment或-e注入 - 敏感值(如
SECRET_KEY)建议用env_file引入,避免硬编码进 YAML 文件
常见踩坑点:build.args 和 environment 写反了
最典型的错误是在 docker-compose.yml 的 build: 下误把运行时配置塞进 args:,结果容器跑起来发现 process.env.DB_PORT 是 undefined。
- 错误写法:
build: args: - DB_PORT=3306→DB_PORT只在构建时存在,镜像里没这个变量 - 正确写法:
environment: - DB_PORT=3306
或配合ENV DB_PORT=3306在Dockerfile中设默认值 - 调试技巧:进容器执行
env | grep DB,确认变量是否真的在运行时环境里 - 额外注意:Docker Desktop GUI 启动的容器,不支持直接设置
build.args,这类参数只能通过 CLI 或 Compose 控制
真正容易被忽略的是:构建参数无法被容器内进程继承,哪怕你用了 ARG + ENV 组合写法,也得确保 ENV 行出现在对应 ARG 声明之后,否则变量为空。这事儿没法靠 GUI 点出来,得看构建日志里有没有 warning。


















