arg仅在构建时生效且不存入镜像,适合传入版本号等一次性参数;env写入镜像并持久化供运行时使用,常通过arg→env级联实现配置传递,多阶段需重复声明arg,敏感信息应避免硬编码env而改用运行时覆盖或secrets。

ARG与ENV的本质分工
ARG只在docker build执行期间起作用,构建一结束就消失,镜像里不留痕迹。它适合传入版本号、临时路径、构建开关这类“一次性”参数。ENV则会写进镜像层,容器启动后依然存在,应用可通过os.Getenv或process.env直接读取,是运行时配置的主力。
用ARG接收输入,再用ENV导出为运行时变量
这是最常用也最关键的级联方式。通过赋值把构建期输入“固化”到运行环境:
-
ARG API_BASE_URL—— 声明构建参数,不设默认值则必须用--build-arg API_BASE_URL=https://prod.api传入 -
ENV API_BASE_URL=${API_BASE_URL}—— 立即把ARG值转为持久环境变量 - 后续所有
RUN指令和最终容器里的应用都能访问$API_BASE_URL
这种写法既避免了硬编码,又确保运行时配置可被外部控制,还不会把敏感值(如密钥)意外暴露在构建日志中——只要不把它直接写死在ENV里。
多阶段构建中ARG需重复声明
每个FROM开启新构建阶段,上一阶段的ARG自动失效。若要在多个阶段使用同一参数,必须每阶段都声明:
ARG NODE_VERSION=18.17.0FROM node:${NODE_VERSION} AS builder-
ARG NODE_VERSION—— 这行不能少,否则第二阶段无法引用 FROM node:${NODE_VERSION}-slim AS runtime
漏掉任一阶段的ARG声明,就会报错“undefined variable”,尤其在从builder复制产物到runtime时容易踩坑。
安全传递敏感信息的推荐路径
密码、令牌等绝不能直接写进ENV,但又需要在运行时可用。推荐组合方案:
- 用
ARG DB_PASSWORD接收,构建时不记录明文(除非显式打印) - 用
ENV DB_PASSWORD=${DB_PASSWORD}导出,供容器内应用连接数据库 - 生产部署时,改用
docker run -e DB_PASSWORD=xxx覆盖,让密码不进镜像 - 更优解:配合
docker secrets或挂载/run/secrets/文件,完全避开环境变量传输
这样既满足构建灵活性,又守住安全底线——ARG管入口,ENV管出口,运行时覆盖兜底。











