DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Docker COPY --from 变量未展开:把参数用于 FROM 并引用阶段别名

COPY --from 的 ARG 变量保留为字面引用,不能用 RUN 的展开结果判断。改成参数化 FROM 来源阶段,再用稳定别名复制文件。

构建参数在 RUN echo 中能显示正确镜像名,COPY --from=${IMAGE_REF} 却报 invalid reference format,甚至出现 repository name must be lowercase。如果报错里的来源仍是字面的 ${IMAGE_REF},应检查 --from 的用法,而不是先把真实仓库名称全部改成小写。

本文适用于 Dockerfile 多阶段构建与当前 Dockerfile 前端。COPY 的源路径、目标路径可以展开环境变量,不代表它的每一个选项都支持同样的替换;--from 不能用这种方式直接插入 ARG 或 ENV 的值。

RUN 能展开,为什么 COPY 的来源不能

下面是有问题的结构示例:

FROM nginx:stable
ARG IMAGE_REF
RUN echo "$IMAGE_REF"
COPY --from=${IMAGE_REF} /staticfiles /usr/share/nginx/html/static

RUN 的 shell 处理自己的变量展开;COPY 由构建器解释,不经过这层 shell。--from 用于指定阶段、命名上下文或镜像来源,不能由一次 RUN 中展开成功来证明它也完成了替换。

先查看完整错误中的引用。若错误就是合法引用以外的 ${...},增加引号、把变量名换成小写,或将 ARG 再写进 ENV 都没有改变选项的机制。如果已经是实际镜像引用,则继续核对仓库名称、标签、拉取权限和源路径,别把另一种拉取失败当作未展开。

用参数定义一个来源阶段

将镜像参数用于 FROM,给这个阶段稳定的别名,再让 COPY 引用别名:

ARG ASSET_IMAGE
FROM ${ASSET_IMAGE} AS assets

FROM nginx:stable
COPY --from=assets /staticfiles /usr/share/nginx/html/static

这是结构示例。构建时需传入一个有效且可拉取的来源镜像,且其中确实有 /staticfiles:

docker build --build-arg ASSET_IMAGE=registry.example.com/team/assets:release -t example-web:release .

registry.example.com/team/assets:release 是镜像引用示例,没有 https:// 前缀。不要把密码塞进构建参数;私有仓库认证使用既有的凭据管理方式。

位于首个 FROM 之前的 ARG 可以供 FROM 使用。这里没有要求它自动进入最终阶段,也不需要为 COPY 再声明一次。assets 是固定别名,COPY 的源路径从这个阶段的文件系统根目录解析,不受该阶段 WORKDIR 的相对路径影响。

来源镜像没有目录时,修复变量用法后仍会失败。应确认镜像版本和构建产物的实际位置,而不是改为本机构建上下文的同名目录;那会悄悄改变复制来源。

验证的是复制来源与产物

保存原 Dockerfile、构建参数和来源镜像标识,先构建新的候选标签,核对来源阶段选择了预期镜像,以及最终静态文件的版本、目录和应用表现。固定版本或摘要时也要保留更新安排,避免只为构建可重复而长期不更新依赖。

若候选产物错误,恢复原构建定义和先前保留的部署镜像;不要直接用新产物覆盖正在运行的站点。成功标准是构建不再解析字面的变量引用,复制到了正确镜像中的预期文件,最终应用使用的是这批产物,而不仅是 RUN echo 输出正常。