Spring Boot2.3 新特性分层JAR的使用

背景

在我们实际生产容器化部署过程中,往往会遇到 Docker 镜像很大,部署发布很慢的情况

影响 docker 镜像大小的因素,主要有以下三个方面:

  1. 基础镜像的大小 。尽量选择 alpine 作为基础镜像 减少操作系统内置软件
  2. Dockerfile 指令层数。 这就要求我们优化 Dockerfile 能合并在一行的尽量合并等
  3. 应用 jar 的大小。这是今天要分享的重点内容

helloworld 镜像

我们先来基于 spring boot 2.3.0 构建一个最简单的 web helloworld,然后构建镜像。

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
ENTRYPOINT ["java", "-jar application.jar"]
docker build --build-arg JAR_FILE=./demo-layer-0.0.1-SNAPSHOT.jar . -t demo:v1.0

查看镜像分层信息

我们通过 docker inspect demo:v1.0 来看下此镜像的每层的散列值

// demo:v1.0 版本镜像分层信息摘要
"Layers": [
  "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
  "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
  "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
  "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
  "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
  "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
  "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
  "sha256:b87d2ff74819f83038ea2f89736a19cfcf99bfa080b8017d191c900a09a7524f"
]

helloworld 升级重新构建

我们对 helloworld 程序进行部分修改(模拟开发过程),然后重新构建镜像

docker build --build-arg JAR_FILE=./demo-layer-0.0.1-SNAPSHOT.jar . -t demo:v1.1

此时镜像分层信息如下 docker inspect demo:v1.1

// demo:v1.1 版本镜像分层信息摘要
"Layers": [
  "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
  "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
  "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
  "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
  "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
  "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
  "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
  "sha256:c1b6350d545fea605e0605c4bfd7f4529cfeee3f6759750d6a5ddeb9c882fc8f"
]

比较 v1.0、v1.1 镜像

通过比较 v1.0 和 v1.1 版本的镜像摘要信息,我们会发现只有最后的一层发生了变化,我们通过 Dive 是一个用 Go 语言编写的 Docker 镜像分析工具来确定一下 最后一层是做了哪些事情
dive demo:v1.0,「大家会看到是最后的 jar 不一样 导致 16M 的内容需要重新构建,当你的业务 jar 很大时,这块就是性能瓶颈」

spring boot 默认打包解密

默认情况下,spring boot 构建出来的 jar ,解压后可以看到如下目录结构。默认会当做一个整体 ,在构建镜像时作为一个单独层,「没有区分业务 classes 和 引用的第三方 jar」

META-INF/
 MANIFEST.MF
org/
 springframework/
  boot/
   loader/
BOOT-INF/
 classes/
 lib/

layer jar

通过上文大家就可以知道分层 jar 的思想就是把,jar 再根据规则细分,业务 class 和 三方 jar 分别对应镜像的不同层,这样改动业务代码,只需变动很少的内容 提高构建速度。

开启分层打包

 <plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
   <layers>
    <enabled>true</enabled>
   </layers>
  </configuration>
 </plugin>

编写支持分层 Dockerfile

核心是通过 spring boot 提供的 layertools 工具,将 jar 进行拆分 然后通过 COPY 指令去分别加载

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM adoptopenjdk:11-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

构建新镜像并查看分层信息

docker build --build-arg JAR_FILE=./demo-layer-0.0.1-SNAPSHOT.jar . -t demo:v2.0
"Layers": [
  "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
  "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
  "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
  "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
  "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
  "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
  "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
  "sha256:06fe18cf8ae7384f120f2c6a3a33b31999dd0460cf1edae45e8f13adeab35942",
  "sha256:16cf814564b8a667fcc9f07314b6084cbef8dc8c0a6565c7a2d91d74faf7e7de",
  "sha256:94be40f716016b68cdd6b99d2cb8154acf8475c3a170a898a22f95a8ef40ffd3",
  "sha256:427d87d6a5fe6da13cb4233939c3a1ff920bc6b4d2f14b5d78af7aef98fda7de"
]

修改代码部分业务代码,重新构建

docker build --build-arg JAR_FILE=./demo-layer-0.0.1-SNAPSHOT.jar . -t demo:v2.1
"Layers": [
  "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
  "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
  "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
  "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
  "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
  "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
  "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
  "sha256:06fe18cf8ae7384f120f2c6a3a33b31999dd0460cf1edae45e8f13adeab35942",
  "sha256:16cf814564b8a667fcc9f07314b6084cbef8dc8c0a6565c7a2d91d74faf7e7de",
  "sha256:94be40f716016b68cdd6b99d2cb8154acf8475c3a170a898a22f95a8ef40ffd3",
  "sha256:8a20c60d361696a4e480fb6fbe1daf8b88bc54c579a98e209da1fb76e25de5aa"
]

查看区别层镜像

最后一层变动大小为 5KB

总结

16MB -> 5KB 变动,在实际开发过程中 效果会更加明显可以通过 spring boot maven plugin 指定分层逻辑,具体可以参考官方文档官方文档: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/maven-plugin/reference/html/

到此这篇关于Spring Boot2.3 新特性分层JAR的使用的文章就介绍到这了,更多相关Spring Boot2.3 分层JAR内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

作者:冷冷zz
链接:https://lltx.github.io

(0)

相关推荐

  • SpringBoot2.3新特性优雅停机详解

    什么是优雅停机 先来一段简单的代码,如下: @RestController public class DemoController { @GetMapping("/demo") public String demo() throws InterruptedException { // 模拟业务耗时处理流程 Thread.sleep(20 * 1000L); return "hello"; } } 当我们流量请求到此接口执行业务逻辑的时候,若服务端此时执行关机 (ki

  • 详解如何用SpringBoot 2.3.0.M1创建Docker映像

    1.发布 SpringBoot2.3.0.M1刚刚发布,它带来了一些有趣的新特性,可以帮助您将SpringBoot应用程序打包到Docker映像中.在这篇博客文章中,我们将查看创建Docker映像的典型方式,并展示如何通过使用这些新特性来改进这些镜像 2.说明 SpringBoot 2.3.0.M1 暂时不支持Windows, 很鸡肋 暂时在Mac 和Linux 上运行良好 3.常见的Docker 运行方式 一般情况下,通过docker 运行springboot 是这样的 FROM openjd

  • Spring Boot2.3 新特性分层JAR的使用

    背景 在我们实际生产容器化部署过程中,往往会遇到 Docker 镜像很大,部署发布很慢的情况 影响 docker 镜像大小的因素,主要有以下三个方面: 基础镜像的大小 .尽量选择 alpine 作为基础镜像 减少操作系统内置软件 Dockerfile 指令层数. 这就要求我们优化 Dockerfile 能合并在一行的尽量合并等 应用 jar 的大小.这是今天要分享的重点内容 helloworld 镜像 我们先来基于 spring boot 2.3.0 构建一个最简单的 web helloworl

  • 简单了解Spring Framework5.0新特性

    SpringFramework5.0是自2013年12月版本4发布之后SpringFramework的第一个主发行版.SpringFramework项目的领导人JuergenHoeller于2016年7月28日宣布了第一个SpringFramework5.0里程碑版本(5.0M1). 现在,将近一年的时间过去以后,我们期盼已久的RC3版本将于2017年7月18日发行.这是路线图规划中SpringFramework5.0首个GA发行版的最后一次发行. 从高层来看,SpringFramework5.

  • Spring各版本新特性的介绍

    Spring各个版本新特性 Spring3.1新特性 1.添加了引入环境profile功能 2.添加了@enable注解,使用特定功能 3.添加了对声明式缓存的支持,能够使用简单的注解声明缓存边界和规则 4.添加的用于构造器注入的c命名空间,类似与Spring2的p命名空间,用于对应属性注入 5.开始支持Servlet3.0,包括基于java配置中生命Servlet和Filter,不再只仅仅借助web.xml 6.改善对于JPA的支持,让JPA能在Spring中完整配置JPA,不必再使用pers

  • Java9版本新特性同一个Jar支持多JDK版本运行

    目录 一.基本使用方法 二.真实的例子 java8代码 Java9代码 编译 运行Mainclass 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 写成一系列的文章,大概十篇左右. java9第一篇-可以在interface中定义私有方法了java9第二篇-Java9改进try-with-resources语法 本文内容:在Java 9增强了J

  • java9新特性Collection集合类的增强与优化方法示例

    目录 一.提供of()方法创建集合 1.1.构建Set集合对象 1.2.构建List集合对象 1.3.构建Map对象 1.4.使用Map.ofEntries()和Map.entry() 二.Arrays 2.1.Arrays.mismatch() 2.2.Arrays.equals() 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 写成一系列的

  • Java9新特性Stream流API优化与增强

    目录 1.Stream.takeWhile(Predicate) 2.Stream.dropWhile(Predicate) 3.StreamStream.iterate(T,Predicate,UnaryOperator) 4.StreamStream.ofNullable(T) 5.IntStream,LongStream和DoubleStream方法 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还

  • Java9新特性Java.util.Optional优化与增强解析

    目录 一.Java9的ifPresentOrElse(Consumer,Runnable) 1.1.Java9中的增强 1.2.回顾一下Java8中的写法 二.Java9的Optional.or(Supplier) 三.Java9的Optional.stream() 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 写成一系列的文章,大概十篇左右,

  • Java9新特性对HTTP2协议支持与非阻塞HTTP API

    目录 一.HTTP/2简介 HTTP/2数据推送 目前支持 HTTP/2 的 Java HTTP 客户端 二.Java 9 的 HTTP/2 客户端 在阻塞模式下发送请求 以非阻塞模式发送请求(Java 9) 三.支持HTTP2的Push-Promise Frames 在HTTP/1.1 发布了16 年之后,IETF在2015年终于通过了HTTP/2 协议.HTTP/2协议旨在降低延迟,满足当今时代对于信息响应时间的要求.在这篇文章中,我会简要的对HTTP/2协议进行介绍,然后我们将重点放在研究

  • Spring Boot2.6.0新特性之默认禁止循环引用

    目录 前言 处理方案一: 处理方案二: 处理方案三: 总结 前言 如下代码,ComponentA类注入ComponentB类,ComponentB类注入ComponentA类,就会发生循环依赖的问题,在2.6.0之前,spring会自动处理循环依赖的问题 import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class ComponentA { @Resou

  • Spring Boot 2.4 新特性之一键构建Docker镜像的过程详解

    背景 在我们开发过程中为了支持 Docker 容器化,一般使用 Maven 编译打包然后生成镜像,能够大大提供上线效率,同时能够快速动态扩容,快速回滚,着实很方便.docker-maven-plugin 插件就是为了帮助我们在 Maven 工程中,通过简单的配置,自动生成镜像并推送到仓库中. spotify .fabric8 这里主要使用的主要是如下两种插件 spotify .fabric8 , - -配置通过 xml 定义出 Dockerfile 或者挂载外部 Dockerfile 通过调用

随机推荐