
本文详解 Docker 多阶段构建中因遗漏 --from 参数导致 target/ 目录无法从构建阶段复制的典型错误,并提供正确写法、关键注意事项及可运行示例。
本文详解 docker 多阶段构建中因遗漏 `--from` 参数导致 `target/` 目录无法从构建阶段复制的典型错误,并提供正确写法、关键注意事项及可运行示例。
在使用 Docker 多阶段构建 Java 应用时,一个常见却隐蔽的错误是:第二阶段 COPY 指令未显式指定来源构建阶段,导致构建产物(如 target/*.jar)未能从第一阶段(build)正确复制,进而引发容器启动失败或“文件不存在”错误。
你的原始 Dockerfile 中这一行:
COPY ./target ./
看似合理,实则存在根本性误解:它试图从宿主机当前目录(即构建上下文中的 ./target)复制文件,而非从上一构建阶段(build)的文件系统中提取。而 Maven 构建产生的 JAR 实际生成在 build 阶段的 /usr/src/app/target/ 路径下——该路径对后续阶段完全不可见,除非显式声明来源。
✅ 正确做法是使用 COPY --from=<stage-name></stage-name> 语法,明确指定跨阶段复制:
FROM maven:3.9.3-amazoncorretto-20 AS build WORKDIR /usr/src/app COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests FROM amazoncorretto:20-alpine-jdk WORKDIR /app COPY --from=build /usr/src/app/target/*.jar app.jar COPY entrypoint.sh . RUN chmod +x entrypoint.sh CMD ["./entrypoint.sh"]
? 关键改进说明:
-
COPY --from=build /usr/src/app/target/*.jar app.jar:精准复制构建阶段生成的唯一 JAR(推荐重命名避免冲突),而非整个target/目录; - 显式
WORKDIR确保路径清晰、行为可预测; -
chmod +x entrypoint.sh避免因权限不足导致脚本无法执行; - 使用
CMD而非ENTRYPOINT(或组合ENTRYPOINT ["sh"]+CMD ["entrypoint.sh"])更利于调试与覆盖命令。
⚠️ 注意事项:
- 若启用 BuildKit(Docker 20.10+ 默认),Docker 会静态分析构建流程;若某构建阶段未被任何
COPY --from引用,该阶段将被完全跳过——这意味着mvn package根本不会执行,target/目录自然不存在; - 始终验证构建阶段输出:可在
build阶段末尾添加RUN ls -la /usr/src/app/target/辅助调试; - 避免
COPY ./target ./这类模糊路径,它依赖宿主机存在已构建产物,破坏了 Docker 的可重现性与隔离性。
总结:多阶段构建的核心价值在于解耦构建环境与运行环境,而 --from 是连接两者的唯一桥梁。漏掉它,就等于切断了构建成果的传递链。务必养成显式声明来源阶段的习惯,让每一行 COPY 都有据可查、可追溯、可验证。


















