Springboot 官方插件构建 Docker 镜像指南
本文通过Springboot官方的maven插件构建Spirng应用的Docker镜像。
我在使用Spring Starter的时候发现了一个新的选项,好像是 Build Native Image,“构建原生 Docker 镜像?”,于是我打算试一试。翻了翻 Springboot 官方文档。发现这是一个使用 Springboot 官方插件构建镜像的东西,我试着写了个 Demo,但是发现每次构建都需要从 Github 上下载 JRE 打包到镜像中去,这太不优雅了(实则众所周知 Github 下载速度奇慢)。花了几个小时找解决方法,包括不限于 Docker 加代理,Maven 加代理,全局加代理。最后依然没有解决这个问题。当时忙于工作,而且这个功能当时只是 beta 版本。遂暂时放弃研究。
后来,我换到新的项目组,负责项目后端几乎所有事务,发现在部署上线时,使用传统 Dockerfile 构建 Docker 镜像的方法真的是太占用服务器磁盘空间了,想方设法压缩镜像大小,但最后还是 500M 起,不够优雅。于是我想到了 Springboot 官方插件构建镜像。恰好当时项目面向海外,CI/CD 服务器也都在海外,没有 Github 下载慢的问题。于是决定再次尝试一次。果不其然,构建成功,而且,镜像竟然只有 300 多 MB。还有自动推送到镜像仓库的功能。果然还是官方的东西好用呐。
在此贴上我首次使用的插件配置示例:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<!--构建docker镜像-->
<image>
<!--镜像名称-->
<name>you-docker-repo-domain/${project.artifactId}:${project.version}
</name>
<!--镜像的网络模式-->
<network>host</network>
<!--打包后推送-->
<publish>true</publish>
</image>
<docker>
<!--推送到仓库-->
<publishRegistry>
<username>YourUserName</username>
<password>YouPassword</password>
<url>https://you-docker-repo-domain</url>
</publishRegistry>
</docker>
</configuration>
</plugin>
后来经过我深入了解,Springboot官方也是结合插件使用Buildpack来构建镜像的,至于BuildPack是什么,有兴趣的可以去这个地址看看。
我们回到正题,虽然使用这种方式构建镜像经过测试没有问题,但是作为一个有点完美主义的人,我还是觉得每次构建镜像都要从Github下载镜像不够优雅。(好吧,其实是每次构建镜像下载JRE占用带宽太高,有点影响CI/CD服务器访问了 摊手.jpg),当时关于BuildPack的资料比较少,没有找到解决问题的办法,就这么凑合用了很久。
当然,这个问题肯定要解决的,其实解决的问题也很简单。只是当时精力都被每天的开发任务消耗完了,没有静下心来好好找。现在时间充裕,精力充沛,这个问题确实很简单就解决了。
这是我跟BuildPack开发人员的一些对话:issues。里面有我成功从本地加载JRE的一个示例,有兴趣可以去看看
省流
首先呢,我们需要从bellsoft-liberica中下载到我们需要使用的JRE到本地。
然后计算这个文件的sha256值。
$ sha256sum /tmp/jre/bellsoft-jre8u312+7-linux-amd64.tar.gz
$ 9850e06b83c891bd96b1b3757e1d04a287800cb4c1e7dc5e3044e1967ce64ef6
用这个值为名创建一个文件
/path/to/you/config/9850e06b83c891bd96b1b3757e1d04a287800cb4c1e7dc5e3044e1967ce64ef6
文件内容为:
file:///tmp/jre/bellsoft-jre8u312+7-linux-amd64.tar.gz
然后还需要创建一个名为type
的文件
/path/to/you/config/type
文件内容为:
dependency-mapping
接着再修改我们项目中的pom.xml
文件,在插件的image
标签下添加以下内容:
<bindings>
<binding>/path/to/you/config/:/platform/bindings/dependency-mapping/</binding>
<binding>/path/to/jre/:/tmp/jre/</binding>
</bindings>
修改后的内容大致为:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<image>
<!-- 略... -->
<bindings>
<binding>/path/to/you/config/:/platform/bindings/dependency-mapping/</binding>
<binding>/path/to/jre/:/tmp/jre/</binding>
</bindings>
</image>
</configuration>
</plugin>
重新运行mvn spring-boot:build-image
从构建日志中我们可以观察到,我们成功的使用本地JRE来构建镜像了。
[INFO] [creator] BellSoft Liberica JRE 8.0.312: Contributing to layer
[INFO] [creator] Downloading from file:///tmp/jre/bellsoft-jre8u312+7-linux-amd64.tar.gz
[INFO] [creator] Verifying checksum
[INFO] [creator] Expanding to /layers/paketo-buildpacks_bellsoft-liberica/jre
参考
- https://docs.spring.io/spring-boot/docs/2.7.11/maven-plugin/reference/htmlsingle/#build-image.customization
- https://paketo.io/docs/reference/java-reference/#optimizations
- https://github.com/paketo-buildpacks/bellsoft-liberica/issues/323
- https://github.com/spring-projects/spring-boot/issues/33417
- https://github.com/dmikusa/binding-tool/issues/38
- How to set dependency-mapping binding in gradle bootBuildImage (Spring-boot 2.7.1, native)