您的位置 首页 java

Spring Boot官方推荐的Docker镜像编译方式-分层jar包

如果你很急着了解,可以直接跳到最后,看最终的 docker file,前面的介绍是为了大家理解原理。

1、普通Dockerfile的缺点

我们通常情况下要编译Spring Boot的 Docker 镜像,一般会写一个下面这样的Dockerfile

 FROM openjdk:17
EXPOSE 8080
ARG JAR_FILE=target/my-application.jar #Maven的位置, Gradle 为build/libs/my-application.jar 
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app. jar "]  

这样做很简单,运行起来也没什么问题,但是它有以下的缺点:

  1. 镜像中的jar包是压缩文件,在容器环境中运行需要解压,这需要相当的开销,我们的jar通常要以解压后的形式运行更好。
  2. 更新程序后编译新的镜像效率低。Docker镜像的编译时分层构建的,而上面将依赖和程序都放在一个层中。在实际应用中,修改程序编译代码的频率将大大高于依赖的变化,所以我们最好将它们分在不同的层,这样不变的层在docker中可以直接使用缓存。

2、一个简单的演示程序

我们创建一个简单的演示应用,添加“Spring Web”。

添加简单的演示代码:

 @SpringBootApplication
@RestController
public class LayeredJarsApplication {
@GetMapping
public String hello(){
return "Hello Layered Jars!";
}

public  static   void  main(String[] args) {
 Spring Application.run(LayeredJarsApplication.class, args);
}

}  

自行编译Spring Boot的jar包。

3、探索官方最佳方案-分层jar包

开始之前,如果你想对Spring Boot的jar包有更深入的了解,可参考我的《 》。

我们打开Spring Boot生成的jar包发现,从Spring Boot 2.3之后,Spring Boot提供了一种新的布局类型叫做“ LAYERED_JAR ”即分层jar包。

在Spring Boot 2.3之后编译的jar包多了一个文件“ layers.idx ”,通过这个文件来提供“层”被添加的顺序。

默认情况下,Spring Boot定义了下面的层:

  1. dependencies :非程序的依赖,但版本号不包含SNAPSHOT。
  2. spring-boot-loader :Spring Boot Jar包加载类。
  3. snapshot-dependencies :非程序的依赖,但版本号包含SNAPSHOT。
  4. application :程序的依赖,应用类和资源。

从layer.idx中可以看到默认的顺序是: dependencies, spring-boot-loader, snapshot-dependencies, application。最少修改的层先添加,修改多的后添加,我们修改最多的应该是应用程序类和资源。

 - "dependencies":
  - "BOOT-INF/lib/"
- "spring-boot-loader":
  - "org/"
- "snapshot-dependencies":
- "application":
  - "BOOT-INF/classes/"
  - "BOOT-INF/classpath.idx"
  - "BOOT-INF/layers.idx"
  - "META-INF/"  

一旦一个分层的jar包被创建后, spring-boot-jarmode-layertools 的jar包会 被添加到应用 程序的依赖中。一旦程序类路径中有了这个jar包,你就可以在特殊模式下启动应用程序,该模式允许引导代码运行与你的应用程序完全不同的东西,例如,提取jar包中层。

4、如何提取层

接上面,我们可以通过 jarmode 系统属性来提取jar包中的层。通过设置 jarmode layertools 来启动jar包从而提取jar包中的层。

控制台运行下面命令:

  java  -Djarmode=layertools -jar my-app.jar  

控制台会提示下面的内容:

 Usage:
  java -Djarmode=layertools -jar layered-jars-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  

我们可以使用list命令列出jar中可提取的层,或者使用extract来提取jar包的层来进行镜像的创建。

5、推荐的Dockerfile

在程序根目录新建Dockerfile,内容如下:

 FROM openjdk:17 as builder
WORKDIR application
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:17
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"]  

这是一个多阶段Dockerfile, builder 阶段提取下面阶段需要的文件夹,每一句 COPY 命令都是我们上面提到的层。

org.springframework.boot.loader.JarLauncher ,是Spring Boot的Main类的入口,想更多了解,可参考《 》。

在Dockerfile下同目录,执行下面命令:

 docker build . --tag layered-jars  

用下面的命令运行docker镜像:

 docker run -it -p8080:8080 layered-jars:latest  

当我们修改程序代码:

 @GetMapping
public String hello(){
return "Hello changed Layered Jars!";
}  

重新编译jar包,执行:

 docker build . --tag layered-jars  

这时我们发现没有被修改过的层都使用缓存了。

再次运行新的镜像:

 docker run -it -p8080:8080 layered-jars:latest  

文章来源:智云一二三科技

文章标题:Spring Boot官方推荐的Docker镜像编译方式-分层jar包

文章地址:https://www.zhihuclub.com/194630.shtml

关于作者: 智云科技

热门文章

网站地图