DOIFOR技术SpringBoot Gradle Plugin配置示例
DOIFOR技术SpringBoot Gradle Plugin配置示例

SpringBoot Gradle Plugin配置示例

技术

今天学习到了一个好东西,分享一下。

springboot从3.0开始支持native编译了,现在已经3.4了,native支持的更加完善了。本文主要介绍以下SpringBoot Gradle Plugin得使用方法,不想看我啰嗦得直接点击查看原文看官方文档。

基于graalvm打包的native镜像有着快速启动,资源占用少的特性,性能上虽然比不上经过jit优化后的程序,但性能输出稳定,与jvm的应用极限性能相差不到10%。

默认情况,如果使用gradle作为构建工具,在装有docker的设备上直接执行bootBuildImage命令就可以打包成native镜像,一般来说最小的spring boot native镜像差不多120M左右,随着业务复杂,引入了更多的依赖,执行文件会略微膨胀,即便如此也比jar包要小很多。

在不做特别的配置性情况,springboot会使用paketobuildpacks/builder-jammy-java-tiny​作为构建工具,并打包出docker.io/libray/projectname:version类似的镜像,由于过程中需要下载以下依赖:

    [creator]     paketo-buildpacks/ca-certificates   3.9.0
    [creator]     paketo-buildpacks/bellsoft-liberica 11.0.1
    [creator]     paketo-buildpacks/syft              2.6.1
    [creator]     paketo-buildpacks/executable-jar    6.12.0
    [creator]     paketo-buildpacks/spring-boot       5.32.0
    [creator]     paketo-buildpacks/native-image      5.15.0

特别时bellsoft 和syft,体积较大,且需要从github上下载,由于国内各种网络原因,基本上下载不下来,因此咱们还需要一些科学上网的手段。不过由于是在容器中进行下载,不好直接设置代理,因此我对宿主机设置了系统级别的代理。

这样确实可以正常编译了,但是,还真有但是啊。科学上网一般都是按流量收费的,不可能每次编译都去下载吧,这一套依赖下来就是1G以上了,编译不了几次就出不去了。

springboot 的Gradle Plugin默认提供了基于volume的缓存,这个缓存默认是与镜像版本相关的,可以保证构建相同版本镜像时只下载依次依赖。但是随着版本变更,这个下载流量也是有些吃不消。对此,Gradle提供了缓存相关的配置,只需要在bootBuildImage任务中增加以下配置即可实现根据应用级的缓存:

bootBuildImage {
    buildWorkspace {
        volume {
            name = "cache-{rootProject.name}.work"
        }
    }
    buildCache {
        volume {
            name = "cache-{rootProject.name}.build"
        }
    }
    launchCache {
        volume {
            name = "cache-${rootProject.name}.launch"
        }
    }
}

上述配置,只要应用名称不变,缓存就一直有效。有没有担心代码变更了,无法正常将新代码打包到镜像中去?

不必担心,我已经替大家验证过了,只要代码发生变更,就会触发graalvm的native-image编译过程。如果未修改代码,则不会执行编译,会直接从缓存中获取上一次编译结果,进行重新打包镜像。

以为这就完了?看看下面这个镜像,能看出什么问题吗?

image

是不是发现创建时间不对劲了?默认情况下,springboot的native镜像不会设置创建时间,因此打包后的时间就是一个默认的值,没有任何意义。因此,咱们还需要在bootBuildImage中添加配置:

bootBuildImage {
    createdDate = "now"
}

这个时间格式为ISO 8601格式,但是“now"例外,使用now就是设置当前时间。

还没完,上面说了,Springboot Gradle Plugin打的镜像名称默认为:docker.io/library/{project.name}:{project.version}

如果我们需要将其推送到私有的制品库,还需要手动打tag。别担心,Spring已经考虑到了,咱们可以对镜像进行一些列的定制。我们可以设置iamgeName属性:

bootBuildImage {
    imageName = "registryhost/doifor/{project.name}:{version}"
}

另外,还可以配置打包完成后进行推送及其认证信息,如下:

bootBuildImage {
    publish = true
    docker {
        publishRegistry {
            url = "registry.cn-chengdu.aliyuncs.com"
            username = "xxxxxxx"
            password = "xxxxxx"
        }
    }
}

不知道各位在做springboot native编译的时候有没有考虑过使用更高性能的设备来加速打包过程?如果代码又不在高性能设备上,该怎么办?将代码拷贝过去,然后安装gradle等环境?springboot默认使用 sock连接本机的docker进行打包,这让我十分的头痛,之前的处理方案就是在开发环境安装一个docker,并且由于默认使用非root用户执行命令,导致构建过程十分痛苦。我记得之前使用maven的docker插件编译时可以设置docker的tcp地址,今天也在这里找到了答案。可以设置docker的host,如下:

bootBuildImage {
    docker {
        host = "tcp://127.0.0.1:2375"
    }
}

完成上述配置就可以痛快的享受Springboot native带来的乐趣了。

不过还是留了个坑没解决,我看官方文档中说可以为构建工具设置代理,但是经过尝试无效,也不知道是我的代理问题还是设置问题,反正就没有正常的从github上把依赖下来下载,官方说可以使用以下配置来进行设置代理:

tasks.named("bootBuildImage") {
    environment["HTTP_PROXY"] = "http://proxy.example.com"
    environment["HTTPS_PROXY"] = "https://proxy.example.com"
}

我配置了,但是没有解决问题,跪求原因,这个问题不解决,以后还是需要首次打包开全局代理,这个还是有些扫兴。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注