当前位置: 首页 > 科技观察

使用SpringBoot创建docker镜像

时间:2023-03-14 01:17:36 科技观察

简介很久以前我们是如何创建SpringBootdocker镜像的?最常见的方式是将Springboot应用打包成一个fatjar,然后写一个docker文件,将fatjar打成docker镜像运行。今天我们就来体验一下SpringBoot2.3.3带来的快速创建docker镜像的功能。传统方法及其缺点现在我们创建一个非常简单的SpringBoot程序:@SpringBootApplication@RestControllerpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}@GetMapping("/getInfo")publicStringgetInfo(){return"www.flydean.com";}}复制代码默认情况下,我们构建的是一个fatjar:springboot-with-docker-0.0.1-SNAPSHOT.jar我们解压看看里面的内容:fatSpringBoot的jar分为三个部分。第一部分是BOOT-INF。里面的class目录就是我们自己写的class文件。lib目录存放项目依赖的其他jar包。第二部分是META-INF,定义了jar包的属性信息。第三部分是SpringBoot的类加载器。fatjar包的启动是通过SpringBoot的jarLauncher创建LaunchedURLClassLoader,通过它加载lib下的jar包,最后以新的线程启动应用程序的Main函数。关于SpringBoot的启动这里就不多说了。来看看,如果要用这个fatjar创建docker镜像怎么写:FROMopenjdk:8-jdk-alpineEXPOSE8080ARGJAR_FILE=target/springboot-with-docker-0.0.1-SNAPSHOT.jarADD${JAR_FILE}app.jarENTRYPOINT["java","-jar","/app.jar"]这样复制代码有两个问题。第一个问题:我们使用的是farjar,在使用farjar的过程中会存在一定的性能问题,肯定比解压后的性能要低,尤其是运行在容器环境下,可能会比较突出。第二个问题:我们知道docker的镜像是分层构建的。逐层构建的好处是可以减少镜像构建的时间,可以复用上一层。但是如果使用fatjar包,即使我们只修改自己的代码,也会导致整个fatjar重新更新,影响docker镜像的构建速度。除了以上两个问题,传统的使用Buildpacks的方法是需要自己构建docker文件。有没有办法一键构建docker镜像?答案是肯定的。SpringBoot在2.3.0之后引入了CloudNativebuildpacks。通过这个工具,我们可以非常非常方便的创建docker镜像。在Maven和Gradle中,SpringBoot引入了一个新的阶段:spring-boot:build-image我们可以直接运行:mvnspring-boot:build-image让代码运行起来,不幸的是,你可能会遇到如下错误:[ERROR]Failed执行goalorg.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:DockerAPI调用'localhost/v1.24/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase-platform-api-0.3'failedwithstatuscode500"InternalServerError"和消息"Gethttps://gcr.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)"->[Help1]复制代码这是因为我们无法从gcr.io中提取图像!没关系,如果你知道如何正确上网,那我估计你找到了代理。将您的代理配置到Docker的代理项中。我使用Docker桌面。以下是我的配置:重新运行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中提取图像。分层Jars如果您不想使用CloudNativeBuildpacks,您仍然想使用传统的Dockerfile。没关系,SpringBoot为我们提供了独特的分层jar包体系。如何打开它?我们需要在POM文件中添加如下配置:true重新打代码包,看jar包内容:和之前的jar包没什么区别,只是多了一个layers.idx的索引文件:-"dependencies":-"BOOT-INF/lib/"-"spring-boot-loader":-"org/"-"snapshot-dependencies":-"application":-"BOOT-INF/classes/"-"BOOT-INF/classpath.idx"-"BOOT-INF/layers.idx"-"META-INF/"复制代码索引文件是主要分为4部分:dependencies-非SNAPSHOT依赖的jar包snapshot-dependencies-SNAPSHOT依赖的jar包spring-boot-loader-Springboot类加载器文件application-应用类和资源文件注意这里的索引文件是有顺序的,这与我们将添加到th的层顺序一致e泊坞窗图像。最先添加变化最少的图层,最后添加变化最多的图层。我们可以使用layertoolsjarmode来验证或者解压生成的fatjar:java-Djarmode=layertools-jarspringboot-with-docker-0.0.1-SNAPSHOT.jarUsage:java-Djarmode=layertools-jarspringboot-with-docker-0.0.1-SNAPSHOT.jar可用命令:listListlayersfromthejartthatcanbeextractedextractExtractslayersfromthejarforimagecreationhelpHelpaboutanycommand复制代码使用list命令,我们可以列出jar包中的图层信息。使用extract我们可以解压不同的层。我们执行解压命令,看一下结果:可以看到我们已经按照layers.idx解压了不同的文件夹。下面看看使用层的dockerFile的写法:FROMadoptopenjdk:11-jre-hotspotasbuilderWORKDIRapplicationARGJAR_FILE=target/*.jarCOPY${JAR_FILE}application.jarRUNjava-Djarmode=layertools-jarapplication.jarextractFROMadoptopenjdk:11-jre-hotspotasbuilderWORKDIRFIapplicationARGJARtarget/*.jarCOPY${JAR_FILE}application.jarRUNjava-Djarmode=layertools-jarapplication.jarextractFROMadoptopenjdk:11-jre-hotspotasbuilderWORKDIRapplication=buillication--app/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文件:"xsi:schemaLocation="http://www.springframework.org/schema/boot/layershttps://www.springframework.org/schema/boot/layers/layers-2.3.xsd">org/springframework/boot/loader/***:*:*SNAPSHOTcom.flydean:*dependenciesspring-boot-loadercompany-dependenciesapplication复制代码这个layer.xml怎么用?只需将其添加到构建插件中即可:启用>真${project.basedir}/src/main/resources/layers.xml