5

spring boot 分层构建镜像

 2 years ago
source link: https://segmentfault.com/a/1190000040213424
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

spring boot 2.3 开始spring-boot-maven-plugin 插件默认开启了分层构建 jar包 或者 war包,本文主要根据官方文档记录一下如何使用分层jar构建镜像。

二、spring-boot-maven-plugin 分层构建 jar 包

配置 spring boot 项目继承自 spring-boot-starter-parent,设置 <parent> 如下:

<!-- Inherit defaults from Spring Boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.1</version>
</parent>

继承自 spring-boot-starter-parent 的项目有如下的默认配置:

  • 默认编译jdk:JDK 1.8
  • 默认编码:UTF-8
  • 默认依赖项管理部分继承自 spring-boot-dependencies POM,管理公共依赖项的版本,这种依赖管理允许您在自己的 POM 中使用时省略那些依赖项的<version>标记
  • 默认配置的 excution goal为:repackage

当在项目中引入 spring-boot-maven-plugin 插件默认就开启了分层构建 jar包,我们可以使用如下方式进行验证:

  • 在项目的 pom.xml 文件中添加如下插件配置:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <artifactId>getting-started</artifactId>
      <!-- ... -->
      <build>
          <plugins>
              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
              </plugin>
          </plugins>
      </build>
    </project>
    
  • 执行如下命令进行打包:

    mvn clean package 

    在 target 目录下面生成对应的 jar 包,解压 jar 包目录结构如下:

image.png

jar 分别在 BOOT-INF/classesBOOT-INF/lib 中包含应用程序的类和依赖项。 类似地,可执行 war 包含 WEB-INF/classes 中的应用程序类和 WEB-INF/lib WEB-INF/lib-provided 中的依赖项。 对于需要从 jar 或 war 的内容构建 docker 镜像的情况,需要分离这些目录以便将它们写入不同的层。

其中的 BOOT-INF/layers.idx 文件就是用来定义分层 jar 的构建顺序的,层的顺序很重要,因为它决定了在应用程序的一部分发生更改时,尽可能将发生更改的内容放在后面,应该先添加最不可能更改的内容,然后再添加最可能更改的层,默认顺序是:

  • dependencies(用于存放不包含 snapshot 的依赖)
  • spring-boot-loader(用于存放类加载器)
  • snapshot-dependencies(用于存放包含 snapshot 的依赖)
  • application(用于存放应用程序的类和资源)

image.png

此分层旨在根据应用程序构建之间更改的可能性来分离代码,项目的依赖不太可能在内部版本之间经常更改,因此将其放置在单独的层dependencies中,以允许工具重新使用缓存中的层,应用程序代码更可能在内部版本之间进行更改,因此将其隔离在单独的层application中。

使用下面的命令查看分层jar 的目录顺序:

java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar list

dependencies
spring-boot-loader
snapshot-dependencies
application

使用下面的命令将jar包按照分层的目录结构进行解压以便创建分层镜像:

java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar extract

关于 java -Djarmode=layertools -jar application.jar 官方的说明如下:

Usage:
  java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar

Available commands:
  list     List layers from the jar that can be extracted
  extract  Extracts layers from the jar for image creation
  help     Help about any command

要禁用此特性,可以采用以下方式


<project>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layers>
                        <enabled>false</enabled>
                    </layers>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

三、多阶段构建 docker 镜像

知道了上面分层 jar 包的构建目录之后,我们可以使用多阶段来构建 docker 镜像,Dockerfile 的内容如下:

# 指定基础镜像,这是多阶段构建的前期阶段
FROM openjdk:11-jre-slim as builder
# 指定工作目录,目录不存在会自动创建
WORKDIR /app
# 将生成的 jar 复制到容器镜像中
COPY target/*.jar application.jar
# 通过工具spring-boot-jarmode-layertools从application.jar中提取拆分后的构建结果
RUN java -Djarmode=layertools -jar application.jar extract

# 正式构建镜像
FROM openjdk:11-jre-slim
# 指定工作目录,目录不存在会自动创建
WORKDIR /app
# 前一阶段从jar中提取除了多个文件,这里分别执行COPY命令复制到镜像空间中,每次COPY都是一个layer
COPY --from=builder app/dependencies ./
COPY --from=builder app/spring-boot-loader ./
COPY --from=builder app/snapshot-dependencies ./
COPY --from=builder app/application ./
# 指定时区
ENV TZ="Asia/Shanghai"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 定义一些环境变量,方便环境变量传参
ENV JVM_OPTS=""
ENV JAVA_OPTS=""
# 指定暴露的端口,起到说明的作用,不指定也会暴露对应端口
EXPOSE 8080
# 启动 jar 的命令
ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

使用下面的命令构建 docker 镜像:

docker build -t demo:1.0.0 . 

使用如下命令查看镜像的分层信息:

docker history demo:1.0.0

image.png

如上图,整个 jar 的内容,例如 class、依赖库、依赖资源等,分多次 COPY 到镜像空间中,所以以后如果只改了class,在更新镜像的时候,只需要下载 class 的 layer 即可(其他 layer 可以直接用之前缓存到本地的)。

image.png

参考文章:

https://docs.spring.io/spring...

https://blog.csdn.net/boling_...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK