ARG 作用域是什么
ARG 声明构建期变量,作用域按阶段划分:写在第一个 FROM 之前的 ARG 只能用在 FROM 行本身,进入某个构建阶段后想用同名变量,必须在 FROM 之后重新声明一次。忘记重声明时变量会静默变成空值,脚本里的路径与版本号随之出问题,而且构建日志不会明确提示,属于典型的「不报错但结果不对」。
基本信息
| 声明语法 | ARG 名称[=默认值] |
|---|---|
| 传值方式 | docker build --build-arg 名称=值 或编排文件的 build.args |
| 作用域 | 按阶段划分;FROM 之前的声明只对该行生效 |
| 重声明要求 | FROM 之后写一条不带赋值的 ARG 名称即可继承传入值 |
| 未声明后果 | 阶段内引用会得到空字符串 |
| 与 ENV 区别 | ARG 只在构建期存在,不写进镜像配置 |
典型使用场景
- 用参数切换基础镜像版本,一套 Dockerfile 适配多个环境
- 多阶段构建中把版本号或下载地址从上游传到下游
- CI 中传入提交号,写入标签或产物路径
- 排查变量为空:确认声明位置是否在对应 FROM 之后
- 区分构建参数与运行时配置,避免把构建期信息带进运行镜像
声明位置与效果
声明位置与效果
# 这行只能用在 FROM 里,阶段内部读不到
ARG BASE=node:20-alpine
FROM ${BASE}
# 正确:进入阶段后重新声明,才能继承构建时传入的值
ARG BASE
ARG APP_VERSION=dev
RUN echo "base=${BASE} version=${APP_VERSION}"
# 错误示范:不重声明,变量为空,脚本静默走错分支
# RUN echo "node ${BASE}" # 输出 node(空值)多阶段传递示例
多阶段传递示例
# syntax=docker/dockerfile:1
ARG ALPINE_VERSION=3.20
FROM alpine:${ALPINE_VERSION} AS build
ARG APP_VERSION
RUN echo "building ${APP_VERSION}" > /out/version.txt
FROM alpine:${ALPINE_VERSION}
ARG APP_VERSION # 每个需要使用的阶段都要重新声明
LABEL org.opencontainers.image.version="${APP_VERSION}"
COPY --from=build /out/version.txt /etc/app/version.txt传参与核对
传参与核对
# 构建时传入参数
docker build --build-arg APP_VERSION=1.4.3 -t app/web:1.4.3 .
# 核对参数是否真的生效:看生成的文件或镜像标签
docker run --rm app/web:1.4.3 cat /etc/app/version.txt
docker image inspect -f '{{json .Config.Labels}}' app/web:1.4.3
# 编排文件里的等价写法:build.args
docker compose build --build-arg APP_VERSION=1.4.3 web常见情况判读
| 情况 | 结果 | 处理方向 |
|---|---|---|
| FROM 之前声明、阶段内使用 | 空值 | 在 FROM 之后重新声明 |
| 多阶段中只在上游声明 | 下游为空 | 每个阶段各自声明 |
| 传入未声明的参数 | 被忽略(部分版本给提示) | 先补声明再传值 |
| 参数用于 FROM 行 | 生效 | 无需在阶段内重声明即可用于该行 |
| 用 ENV 代替 ARG | 值留在镜像里 | 构建期参数请用 ARG |
ARG 的值会出现在构建历史与镜像元数据里(部分形式),因此不适合传递密钥;需要保密的构建期信息应通过挂载临时文件或外部构建服务注入。
编排文件里 build.args 支持引用插值变量,例如把项目级变量传入构建,这样一套文件即可服务多个环境。