文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用Spring Boot创建docker image

2024-12-03 18:49

关注

 简介
在很久很久以前,我们是怎么创建Spring Boot的docker image呢?最最通用的办法就是将Spring boot的应用程序打包成一个fat jar,然后写一个docker file,将这个fat jar制作成为一个docker image然后运行。

今天我们来体验一下Spring Boot 2.3.3 带来的快速创建docker image的功能。

传统做法和它的缺点
现在我们创建一个非常简单的Spring Boot程序:

  1. @SpringBootApplication 
  2. @RestController 
  3. public class Application { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(Application.class, args); 
  7.     } 
  8.  
  9.     @GetMapping("/getInfo"
  10.     public String getInfo() { 
  11.         return "www.flydean.com"
  12.     } 
  13. 复制代码 

默认情况下,我们build出来的是一个fat jar:springboot-with-docker-0.0.1-SNAPSHOT.jar

我们解压看一下它的内容:

Spring boot的fat jar分为三个部分,第一部分就是BOOT-INF, 里面的class目录放的是我们自己编写的class文件。而lib目录存放的是项目依赖的其他jar包。

第二部分是META-INF,里面定义了jar包的属性信息。

第三部分是Spring Boot的类加载器,fat jar包的启动是通过Spring Boot的jarLauncher来创建LaunchedURLClassLoader,通过它来加载lib下面的jar包,最后以一个新线程启动应用的Main函数。

这里不多讲Spring Boot的启动。

我们看一下,如果想要用这个fat jar来创建docker image应该怎么写:

  1. FROM openjdk:8-jdk-alpine 
  2. EXPOSE 8080 
  3. ARG JAR_FILE=target/springboot-with-docker-0.0.1-SNAPSHOT.jar 
  4. ADD ${JAR_FILE} app.jar 
  5. ENTRYPOINT ["java","-jar","/app.jar"
  6. 复制代码 

这样写有两个问题。

第一个问题:我们是用的far jar,在使用far jar的过程中会有一定的性能问题,肯定要比解压过后的性能要低,尤其是在容器环境中运行的情况下,可能会更加突出。

第二个问题:我们知道docker的image是按layer来构建的,按layer构建的好处就是可以减少image构建的时间和重用之前的layer。

但是如果使用的是fat jar包,即使我们只修改了我们自己的代码,也会导致整个fat jar重新更新,从而影响docker image的构建速度。

使用Buildpacks
传统的办法除了有上面的两个问题,还有一个就是需要自己构建docker file,有没有一键构建docker image的方法呢?

答案是肯定的。

Spring Boot在2.3.0之后,引入了Cloud Native 的buildpacks,通过这个工具,我们可以非常非常方便的创建docker image。

在Maven和Gradle中,Spring Boot引入了新的phase: spring-boot:build-image

我们可以直接运行:

  1. mvn  spring-boot:build-image 
  2. 制代码 

运行之,很不幸的是,你可能会遇到下面的错误:

  1. [ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) on project springboot-with-docker: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-image failed: Docker API call to 'localhost/v1.24/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase-platform-api-0.3' failed with status code 500 "Internal Server Error" and message "Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)" -> [Help 1] 
  2. 复制代码 

这是因为我们无法从gcr.io中拉取镜像!

没关系,如果你会正确的上网方式的话,那么我估计你已经找到了一个代理。

将你的代理配置到Docker的代理项里面,我使用的是Docker desktop,下面是我的配置:

重新运行 mvn spring-boot:build-image

等待执行结果:

  1. [INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) @ springboot-with-docker --- 
  2. [INFO] Building image 'docker.io/library/springboot-with-docker:0.0.1-SNAPSHOT' 
  3. [INFO]  
  4. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  5. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  6. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  7. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  8. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  9. [INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0% 
  10. 复制代码 

你可以看到,我们的确是需要从gcr.io拉取image。

Layered Jars
如果你不想使用Cloud Native Buildpacks,还是想使用传统的Dockerfile。 没关系,SpringBoot为我们提供了独特的分层jar包系统。

怎么开启呢? 我们需要在POM文件中加上下面的配置:

  1.  
  2.         
  3.             
  4.                org.springframework.boot 
  5.                spring-boot-maven-plugin 
  6.                 
  7.                     
  8.                        true 
  9.                     
  10.                 
  11.             
  12.         
  13.     
  14. 制代码 

再次打包,看下jar包的内容:

看起来和之前的jar包没什么不同,只不过多了一个layers.idx 这个index文件:

  1. "dependencies"
  2.   - "BOOT-INF/lib/" 
  3. "spring-boot-loader"
  4.   - "org/" 
  5. "snapshot-dependencies"
  6. "application"
  7.   - "BOOT-INF/classes/" 
  8.   - "BOOT-INF/classpath.idx" 
  9.   - "BOOT-INF/layers.idx" 
  10.   - "META-INF/" 
  11. 复制代码 

index文件主要分为4个部分:

注意,这里的index文件是有顺序的,它和我们将要添加到docker image中的layer顺序是一致的。

最少变化的将会最先添加到layer中,变动最大的放在最后面的layer。

我们可以使用layertools jarmode来对生成的fat jar进行校验或者解压缩:

  1. java -Djarmode=layertools -jar springboot-with-docker-0.0.1-SNAPSHOT.jar  
  2. Usage: 
  3.   java -Djarmode=layertools -jar springboot-with-docker-0.0.1-SNAPSHOT.jar 
  4.  
  5. Available commands: 
  6.   list     List layers from the jar that can be extracted 
  7.   extract  Extracts layers from the jar for image creation 
  8.   help     Help about any command 
  9. 复制代码 

使用list命令,我们可列出jar包中的layer信息。使用extract我们可以解压出不同的layer。

我们执行下extract命令,看下结果:

可以看到,我们根据layers.idx解压出了不同的文件夹。

我们看一下使用layer的dockerFile应该怎么写:

  1. FROM adoptopenjdk:11-jre-hotspot as builder 
  2. WORKDIR application 
  3. ARG JAR_FILE=target/*.jar 
  4. COPY ${JAR_FILE} application.jar 
  5. RUN java -Djarmode=layertools -jar application.jar extract 
  6.  
  7. FROM adoptopenjdk:11-jre-hotspot 
  8. WORKDIR application 
  9. COPY --from=builder application/dependencies/ ./ 
  10. COPY --from=builder application/spring-boot-loader/ ./ 
  11. COPY --from=builder application/snapshot-dependencies/ ./ 
  12. COPY --from=builder application/application/ ./ 
  13. ENTRYPOINT ["java""org.springframework.boot.loader.JarLauncher"
  14. 复制代码 

这样我们的一个分层的DockerImage就创建完成了。

自定义Layer
如果我们需要自定义Layer该怎么做呢?

我们可以创建一个独立的layers.xml文件:

  1. "http://www.springframework.org/schema/boot/layers" 
  2.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  3.         xsi:schemaLocation="http://www.springframework.org/schema/boot/layers 
  4.               https://www.springframework.org/schema/boot/layers/layers-2.3.xsd"> 
  5.      
  6.         <into layer="spring-boot-loader"
  7.             org/springframework/boot/loader/** 
  8.         into
  9.         <into layer="application" /> 
  10.      
  11.      
  12.         <into layer="snapshot-dependencies"
  13.             *:*:*SNAPSHOT 
  14.         into
  15.         <into layer="company-dependencies"
  16.             com.flydean:* 
  17.         into
  18.         <into layer="dependencies"/> 
  19.      
  20.      
  21.         dependencies 
  22.         spring-boot-loader 
  23.         snapshot-dependencies 
  24.         company-dependencies 
  25.         application 
  26.      
  27.  
  28. 复制代码 

怎么使用这个layer.xml呢?

添加到build plugin中就可以了:

  1.  
  2.         
  3.             
  4.                org.springframework.boot 
  5.                spring-boot-maven-plugin 
  6.                 
  7.                     
  8.                        true 
  9.                        ${project.basedir}/src/main/resources/layers.xml 
  10.                     
  11.                 
  12.             
  13.         
  14.     

 

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯