以下是一个基于 Spring Boot 源码构建并部署应用的 Containerfile 示例,采用多阶段构建(先编译源码,再运行应用),最终镜像体积更小,适合生产环境。
假设你的 Spring Boot 项目结构如下(标准 Maven 项目结构),如下图:

my-app/ ├── Containerfile # 本文要创建的构建文件 ├── pom.xml # Maven 配置文件(或 build.gradle 用于 Gradle) └── src/ # 源代码目录 └── main/ ├── java/ # Java 源代码 └── resources/ # 配置文件(如 application.properties)
点击下载项目源码:
my_app.zip
下面是 Containerfile 文件内容如下:
# 第一阶段:使用Maven编译打包项目 FROM library/maven:3.8.5-openjdk-17-slim AS builder # 设置工作目录 WORKDIR /app # 复制项目依赖文件 COPY pom.xml . # 下载依赖(利用Maven缓存机制,加快后续构建) RUN mvn dependency:go-offline -B # 复制源代码 COPY src ./src # 编译打包(跳过测试以加快构建) RUN mvn package -DskipTests # 第二阶段:运行Spring Boot应用 FROM library/openjdk:26-ea-17-slim # 设置工作目录 WORKDIR /app # 从构建阶段复制打包好的jar文件 COPY --from=builder /app/target/*.jar app.jar # 暴露8080端口 EXPOSE 8080 # 启动命令 ENTRYPOINT ["java", "-jar", "app.jar"]
详细说明:
(1)多阶段构建
第一阶段(builder)使用包含 Maven 和 JDK 的镜像编译源码,生成 JAR 包。
第二阶段仅使用 JRE 镜像(体积更小,减少攻击面),仅复制第一阶段的 JAR 包,最终镜像体积可减少 70% 以上。
(2)JAR 文件名处理
如果你的项目打包后的 JAR 文件名不固定(如带版本号),可在 pom.xml 中配置固定名称:
<build> <finalName>app</finalName> <!-- 固定为 app.jar --> </build>
此时 COPY 命令可简化为 COPY --from=builder /app/target/app.jar app.jar。
(3)依赖缓存优化
先复制 pom.xml 并执行 mvn dependency:go-offline,确保依赖仅在 pom.xml 变动时重新下载,加速后续构建。
注意,mvn dependency:go-offline 是 Maven 的一个核心插件目标,核心作用是提前下载项目构建所需的所有依赖(包括编译依赖、测试依赖、插件依赖等)并缓存到本地仓库,让项目后续构建可以脱离网络环境(离线)进行。
(4)端口暴露
EXPOSE 8080 仅声明容器内应用监听的端口,实际运行时需通过 -p 映射到宿主机(如 podman run -p 8080:8080 ...)。
在 Containerfile 所在目录执行如下命令:
podman build -t my-springboot-app:1.0 .
镜像构建详细日志如下:
C:\Users\hxstri\my_app> podman build -t my-springboot-app:1.0 . 下载JDK镜像 [1/2] STEP 1/6: FROM library/maven:3.8.5-openjdk-17-slim AS builder Resolving "library/maven" using unqualified-search registries (/home/user/.config/containers/registries.conf) Trying to pull docker.io/library/maven:3.8.5-openjdk-17-slim... Getting image source signatures Copying blob sha256:8cf4021f808970ac7512edfd6f771e6ae535beeb47883bc9baa81aa9470657f4 ... Writing manifest to image destination [1/2] STEP 2/6: WORKDIR /app --> 3f6c757b2c99 [1/2] STEP 3/6: COPY pom.xml . --> 66aa43392961 开始下载 maven 依赖 [1/2] STEP 4/6: RUN mvn dependency:go-offline -B [INFO] Scanning for projects... [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/3.4.11/spring-boot-starter-parent-3.4.11.pom ... [INFO] Resolved dependency: logback-classic-1.5.20.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 10:04 min [INFO] Finished at: 2025-11-18T08:40:08Z [INFO] ------------------------------------------------------------------------ --> 6422be08142e 复制源码且进行源码编译 [1/2] STEP 5/6: COPY src ./src --> a708c6014c88 [1/2] STEP 6/6: RUN mvn package -DskipTests [INFO] Scanning for projects... [INFO] [INFO] ------------------------< com.hxstrive:my_app >------------------------- [INFO] Building my_app 0.0.1-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- Downloading from central: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-core/2.18.4.1/jackson-core-2.18.4.1.pom ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 14.479 s [INFO] Finished at: 2025-11-18T08:40:29Z [INFO] ------------------------------------------------------------------------ --> 28f17de3ba15 下载运行应用的JDK基础镜像 [2/2] STEP 1/5: FROM library/openjdk:26-ea-17-slim Resolving "library/openjdk" using unqualified-search registries (/home/user/.config/containers/registries.conf) Trying to pull docker.io/library/openjdk:26-ea-17-slim... Getting image source signatures ... Writing manifest to image destination [2/2] STEP 2/5: WORKDIR /app --> 7a44790e4950 [2/2] STEP 3/5: COPY --from=builder /app/target/*.jar app.jar --> cde53a5e81b6 [2/2] STEP 4/5: EXPOSE 8080 --> 3d81e0f766c1 [2/2] STEP 5/5: ENTRYPOINT ["java", "-jar", "app.jar"] [2/2] COMMIT my-springboot-app:1.0 --> 7cb487c53d85 Successfully tagged localhost/my-springboot-app:1.0 7cb487c53d85ec684aab1af3bba401c5cc7a3f907e1f8fd2b635e6a355554eb3
镜像编译完成后,通过 podman images 命令查看镜像信息:
C:\Users\hxstri\my_app> podman images | findstr my-springboot-app localhost/my-springboot-app 1.0 7cb487c53d85 4 minutes ago 514 MB
使用 podman run 命令启动一个容器,映射宿主机 8080 端口到容器 8080 端口,如下:
podman run -d -p 8080:8080 --name my-spring-app my-springboot-app:1.0
详细日志:
C:\Users\hxstri\my_app> podman run -d -p 8080:8080 --name my-spring-app my-springboot-app:1.0 ea4edb8f07e3301d6ddde31dda347020f393d3041aaac52bf755a4caf5fa9729 C:\Users\hxstri\my_app> podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea4edb8f07e3 localhost/my-springboot-app:1.0 6 seconds ago Up 6 seconds 0.0.0.0:8080->8080/tcp my-spring-app
验证应用是否启动,打开浏览器访问 http://localhost:8080 地址,如下图:

访问正常,镜像构建成功。