利用Spring Boot创建docker image的完整步骤
前言
在很久很久以前,我们是怎么创建SpringBoot的dockerimage呢?最最通用的办法就是将Springboot的应用程序打包成一个fatjar,然后写一个dockerfile,将这个fatjar制作成为一个dockerimage然后运行。
今天我们来体验一下SpringBoot2.3.3带来的快速创建dockerimage的功能。
传统做法和它的缺点
现在我们创建一个非常简单的SpringBoot程序:
@SpringBootApplication @RestController publicclassApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(Application.class,args); } @GetMapping("/getInfo") publicStringgetInfo(){ return"www.flydean.com"; } }
默认情况下,我们build出来的是一个fatjar:springboot-with-docker-0.0.1-SNAPSHOT.jar
我们解压看一下它的内容:
Springboot的fatjar分为三个部分,第一部分就是BOOT-INF,里面的class目录放的是我们自己编写的class文件。而lib目录存放的是项目依赖的其他jar包。
第二部分是META-INF,里面定义了jar包的属性信息。
第三部分是SpringBoot的类加载器,fatjar包的启动是通过SpringBoot的jarLauncher来创建LaunchedURLClassLoader,通过它来加载lib下面的jar包,最后以一个新线程启动应用的Main函数。
这里不多讲SpringBoot的启动。
我们看一下,如果想要用这个fatjar来创建dockerimage应该怎么写:
FROMopenjdk:8-jdk-alpine EXPOSE8080 ARGJAR_FILE=target/springboot-with-docker-0.0.1-SNAPSHOT.jar ADD${JAR_FILE}app.jar ENTRYPOINT["java","-jar","/app.jar"]
这样写有两个问题。
第一个问题:我们是用的farjar,在使用farjar的过程中会有一定的性能问题,肯定要比解压过后的性能要低,尤其是在容器环境中运行的情况下,可能会更加突出。
第二个问题:我们知道docker的image是按layer来构建的,按layer构建的好处就是可以减少image构建的时间和重用之前的layer。
但是如果使用的是fatjar包,即使我们只修改了我们自己的代码,也会导致整个fatjar重新更新,从而影响dockerimage的构建速度。
使用Buildpacks
传统的办法除了有上面的两个问题,还有一个就是需要自己构建dockerfile,有没有一键构建dockerimage的方法呢?
答案是肯定的。
SpringBoot在2.3.0之后,引入了CloudNative的buildpacks,通过这个工具,我们可以非常非常方便的创建dockerimage。
在Maven和Gradle中,SpringBoot引入了新的phase:spring-boot:build-image
我们可以直接运行:
mvnspring-boot:build-image
运行之,很不幸的是,你可能会遇到下面的错误:
[ERROR]Failedtoexecutegoalorg.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-image(default-cli)onprojectspringboot-with-docker:Executiondefault-cliofgoalorg.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-imagefailed:DockerAPIcallto'localhost/v1.24/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase-platform-api-0.3'failedwithstatuscode500"InternalServerError"andmessage"Gethttps://gcr.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)"->[Help1]
这是因为我们无法从gcr.io中拉取镜像!
没关系,如果你会正确的上网方式的话,那么我估计你已经找到了一个代理。
将你的代理配置到Docker的代理项里面,我使用的是Dockerdesktop,下面是我的配置:
重新运行mvnspring-boot:build-image
等待执行结果:
[INFO]---spring-boot-maven-plugin:2.3.3.RELEASE:build-image(default-cli)@springboot-with-docker---
[INFO]Buildingimage'docker.io/library/springboot-with-docker:0.0.1-SNAPSHOT'
[INFO]
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
[INFO] >Pullingbuilderimage'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3'0%
你可以看到,我们的确是需要从gcr.io拉取image。
LayeredJars
如果你不想使用CloudNativeBuildpacks,还是想使用传统的Dockerfile。没关系,SpringBoot为我们提供了独特的分层jar包系统。
怎么开启呢?我们需要在POM文件中加上下面的配置:
org.springframework.boot spring-boot-maven-plugin true
再次打包,看下jar包的内容:
看起来和之前的jar包没什么不同,只不过多了一个layers.idx这个index文件:
-"dependencies": -"BOOT-INF/lib/" -"spring-boot-loader": -"org/" -"snapshot-dependencies": -"application": -"BOOT-INF/classes/" -"BOOT-INF/classpath.idx" -"BOOT-INF/layers.idx" -"META-INF/"
index文件主要分为4个部分:
- dependencies–非SNAPSHOT的依赖jar包
- snapshot-dependencies–SNAPSHOT的依赖jar包
- spring-boot-loader–Springboot的classloader文件
- application–应用程序的class和resources文件
注意,这里的index文件是有顺序的,它和我们将要添加到dockerimage中的layer顺序是一致的。
最少变化的将会最先添加到layer中,变动最大的放在最后面的layer。
我们可以使用layertoolsjarmode来对生成的fatjar进行校验或者解压缩:
java-Djarmode=layertools-jarspringboot-with-docker-0.0.1-SNAPSHOT.jar Usage: java-Djarmode=layertools-jarspringboot-with-docker-0.0.1-SNAPSHOT.jar Availablecommands: listListlayersfromthejarthatcanbeextracted extractExtractslayersfromthejarforimagecreation helpHelpaboutanycommand
使用list命令,我们可列出jar包中的layer信息。使用extract我们可以解压出不同的layer。
我们执行下extract命令,看下结果:
可以看到,我们根据layers.idx解压出了不同的文件夹。
我们看一下使用layer的dockerFile应该怎么写:
FROMadoptopenjdk:11-jre-hotspotasbuilder WORKDIRapplication ARGJAR_FILE=target/*.jar COPY${JAR_FILE}application.jar RUNjava-Djarmode=layertools-jarapplication.jarextract FROMadoptopenjdk:11-jre-hotspot WORKDIRapplication COPY--from=builderapplication/dependencies/./ COPY--from=builderapplication/spring-boot-loader/./ COPY--from=builderapplication/snapshot-dependencies/./ COPY--from=builderapplication/application/./ ENTRYPOINT["java","org.springframework.boot.loader.JarLauncher"]
这样我们的一个分层的DockerImage就创建完成了。
自定义Layer
如果我们需要自定义Layer该怎么做呢?
我们可以创建一个独立的layers.xml文件:
org/springframework/boot/loader/** *:*:*SNAPSHOT com.flydean:* dependencies spring-boot-loader snapshot-dependencies company-dependencies application
怎么使用这个layer.xml呢?
添加到buildplugin中就可以了:
org.springframework.boot spring-boot-maven-plugin true ${project.basedir}/src/main/resources/layers.xml
本文的例子:springboot-with-docker
总结
到此这篇关于利用SpringBoot创建dockerimage完整步骤的文章就介绍到这了,更多相关SpringBoot创建dockerimage内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。