贝利信息

如何在 Docker 容器中正确构建并运行 Maven 项目

日期:2025-12-25 00:00 / 作者:碧海醫心

本文详解如何通过多阶段构建在 docker 中安全、高效地编译 maven 项目,并解决因路径不一致导致的 `lstat target: no such file or directory` 构建错误。

在 Docker 中构建 Java 应用时,使用 Maven 多阶段构建(multi-stage build)是最佳实践:第一阶段负责编译和打包,第二阶段仅包含运行时依赖(如 JRE),从而显著减小镜像体积、提升安全性与可移植性。但实践中,一个常见陷阱是未正确指定构建产物的来源路径,导致 COPY target/*.jar 失败——正如错误信息所示:lstat /var/lib/docker/tmp/buildkit-mount.../target: no such file or directory。

根本原因在于:Docker 的 COPY 指令在非构建阶段(即第二阶段)中无法直接访问前

一阶段(builder)的工作目录或文件系统。你不能像本地开发那样假设 target/ 目录天然存在;必须显式声明从哪个构建阶段(--from=builder)复制哪些文件,并提供绝对路径

✅ 正确做法是使用 COPY --from= 语法,精准定位 builder 阶段中生成的 JAR 文件。由于你在 builder 阶段设置了 WORKDIR /tmp/,Maven 执行 mvn clean install 后,输出 JAR 必然位于 /tmp/target/ 下(例如 /tmp/target/myapp-1.0.0-SNAPSHOT.jar)。因此,第二阶段应直接从该路径复制:

FROM maven:3.8.1-openjdk-17 AS builder
COPY src/ /tmp/src/
COPY pom.xml /tmp/
WORKDIR /tmp
RUN mvn clean install -B  # -B 启用批处理模式,避免交互提示

FROM openjdk:17-jre-slim  # ⚠️ 关键优化:改用精简 JRE 镜像,而非完整 Maven 镜像
WORKDIR /app
COPY --from=builder /tmp/target/*.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "app.jar"]

? 关键改进说明:

⚠️ 注意事项:

总结:Docker 多阶段构建不是“连续 shell 会话”,每个阶段拥有独立文件系统。务必用 --from 明确阶段间依赖,并用绝对路径定位产物。遵循此原则,即可稳定实现 Maven 项目的容器化构建与轻量部署。