Podman 教程

Containerfile 实战:自己的 Spring Boot 镜像(基于源码)

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

目录结构

假设你的 Spring Boot 项目结构如下(标准 Maven 项目结构),如下图:

Containerfile 实战:自己的 Spring Boot 镜像(基于源码)

my-app/
├── Containerfile          # 本文要创建的构建文件
├── pom.xml                # Maven 配置文件(或 build.gradle 用于 Gradle)
└── src/                   # 源代码目录
    └── main/
        ├── java/          # Java 源代码
        └── resources/     # 配置文件(如 application.properties)

点击下载项目源码:my_app.zip

  

Containerfile 内容

下面是 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 地址,如下图:

Containerfile 实战:自己的 Spring Boot 镜像(基于源码)

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

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号