体验springboot服务docker打包分层

前言

随着云原生技术的发展,现在大部分企业项目都通过容器化来部署项目,不管是docker部署还是k8s都离不开打镜像的环节,传统打镜像的方式通常时间上会比较漫长,有时候改动少量代码就需要全部打包。今天来体验一下Springboot2.3.0后的分层打包功能。

普通打包

我们先新建一个添加了springboot依赖的maven测试项目,对于诸位老Javaboy来说属于闭着眼操作了,默认的maven项目里一般不会自动添加上打包插件。最开始接触springboot的时候使用maven package打出来jar包启动会发现报错找不到入口类。

所以一定要在pom中加上

org.springframework.boot
spring-boot-maven-plugin
com.uptown.sign.SignApplication
ZIP
true
true
repackage

随便写一个hello world的控制器入口,然后直接编写Dockerfile文件

FROM openjdk:8-jdk-alpine
# 打包命令
RUN mvn package
# 声明一个端口但不真正运行在这个端口
EXPOSE 8080
# 把打出来的包添加到镜像中
ADD target/*.jar ./app.jar
# 执行命令
CMD java -jar app.jar

完事之后运行命令打成镜像测试

docker build . -t test:0.0.1

打出镜像后查看镜像的分层结构。

docker inspect test:0.0.1

图片

图中的Layers就是镜像层,docker是会按命令分层,我们把hello world改成fuck work,重新执行下上述步骤再docker inspect分析下新镜像的Layers会发现

图片

你会发现这些Layers中只有最后一处与旧镜像内容不一样,我们仅仅只改动了一个接口返回的文案,重新打包后会把所有动作重新都做一边,做完后发现打出来的镜像每层基本都一样,只有最后一层有变化,那么我们能不能只重新制作有变化的包呢。

分层打包

当然是可以了,这就是springboot在230加的新特性,虽然现在springboot版本已经出道3了,但是我认为越迭代越重,加了很多可有可无的东西,不如老版本中一些好用的特性值得把玩。

根本原理其实是一个springboot打出jar包中主要包含四个部分,自己写的代码,第三方依赖、SpringBoot内部配置、快照依赖 ,如果仅仅只是改动了自己写的代码的话那其他那三部分根本不用变。也就是说如果你换了依赖版本那就不行了。

首先在pom中打开分层开关

org.springframework.boot
spring-boot-maven-plugin
true

再用mvn package打包之后我们用命令分析下jar包内容

java -Djarmode=layertools -jar target/dockers-demo-0.0.1-SNAPSHOT.jar list

图片

这里就分别对应了上述那四个部分代码,所以如果只更改部分代码的话并不需要再将依赖相关的代码编译上次编译完的直接用呗。

FROM openjdk:8-jdk-alpine
RUN mvn package
ADD target/*.jar ./app.jar
RUN java -Djarmode=layertools -jar app.jar extract
FROM openjdk:8-jre
WORKDIR application
# 复制第三方依赖、SpringBoot内部配置、快照依赖
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"]

改造后你再去打包会发现特别快,springboot好用就在于内置了很多依赖包,跨过依赖包单独打业务代码快的一批,但是仅在依赖版本未发生变更的场景下生效。