使用Jib for Spring Boot优化Docker存储库中的映像存储

使用Jib构建Docker映像是否有助于优化远程Docker存储库存储?

我们在带有Gradle的Docker中使用Spring Boot。当前,我们正在创建带有所有依赖项的标准胖启动jar,然后使用它创建映像,如下所示:

FROM gcr.io/distroless/java:11
COPY ./build/libs/*.jar app.jar
CMD ["app.jar"]

即使实际上只更改了很少的代码,每次构建时也会产生较大的(250 MB)新映像。这是因为胖子罐包含共享的依赖项(不经常更改)和我们的代码。这是私有存储库中存储空间的低效使用,我们希望对此进行更改。

为此,想法如下:

  • 我们创建一个基本映像,该映像仅包含/ opt / libs中的依赖项,我们将其称为spring-base:1.0.0并推送到我们的私有Docker注册表。

  • 我们使用该图像作为仅包含我们代码的应用程序图像的父级/基础。 Dockerfile看起来与此类似(未经演示,仅用于介绍概念):

    FROM our-registry/spring-base:1.0.0
    COPY ./build/classes/kotlin/main/* /opt/classes
    COPY ./build/resources/main/* /opt/resources
    ENTRYPOINT ["java","-cp","/opt/libs/*:/opt/resources:/opt/classes","com.example.MainKt"]
    

期望这些图像要小得多,并且具有依赖性的大型基础图像仅存储一次,从而节省了大量存储空间。

我们的一位同事调查了Jib并坚持要做到这一点,但是在阅读了整个文档和FAQ并进行了一些尝试之后,我不确定。我们将其集成并使用./gradlew jibDockerBuild,它似乎确实为依赖项,资源和类创建了层,但是仍然只有一个大的形象。 Jib似乎专注于加快构建时间(通过利用Docker层缓存)和可复制的构建,但是我认为,当我们将该映像上传到我们的存储库时,相对于我们当前的解决方案不会有任何变化-我们仍将存储“静态”依赖项多次,但是现在我们将具有多层,而不是每个新图像中只有一层。

任何具有Docker和Jib经验的人都可以解释Jib是否为我们提供了我们正在寻找的存储空间优化?

编辑:在我等待答案时,我尝试了所有这些操作,并使用https://github.com/wagoodman/divedocker system dfdocker images检查大小和查看图像和图层,看来Jib确实满足了我们的需要。

zzz34486199 回答:使用Jib for Spring Boot优化Docker存储库中的映像存储

使用Jib构建Docker映像是否有助于优化远程Docker存储库存储?

是的。实际上,由于强大的图像层可重复性,它在很大程度上帮助了这一点。仅使用Dockerfile时,通常会完全丧失大多数图层的可重复性,因为文件时间戳记会影响检查图层是否相同。例如,即使您的.class的字节完全没有变化,如果再次生成该文件,也将失去可重复性。这对于罐子来说更糟;不仅其时间戳可以更改,而且jar元数据(例如META-INF/MANIFEST.MF)还包含编译时信息,包括时间戳,构建工具信息,JVM版本等。在其他计算机上构建的jar将被认为是不同的。 Docker世界。

即使实际上只更改了很少的代码,每次构建时也会产生较大的(250 MB)新映像。这是因为胖子包含共享的依赖关系(不经常更改)和我们的代码。

部分纠正大小大(250MB)的问题,但不是因为有胖子。即使它不是一个胖子,即使您为共享库指定了不同的层,生成的映像的大小也将始终为250MB。最终映像的大小(250MB)将始终包括基础映像的大小(gcr.io/distroless/java:11)和共享库的大小,无论使用哪种工具构建映像的方式都是如此。

但是,Docker引擎不会复制其在存储中已经知道的层。同样,远程注册表也不复制存储库中已经存在的层。此外,注册管理机构通常甚至在不同的存储库中只存储一层的精确副本。因此,当您仅更新代码(因此更新了jar)时,只有包含该jar的层会占用新的存储空间。 Docker和Jib将仅通过网络将新层发送到远程注册表。也就是说,gcr.io/distroless/java:11的基本图像层将不会发送。

我们创建一个仅包含/ opt / libs中依赖项的基础映像,我们将其称为spring-base:1.0.0并推送到我们的私有Docker注册表。

创建一个单独的映像以仅包含共享库并不是闻所未闻的,而且我已经看到有人尝试这样做。但是,我不认为您打算在概念上将此特殊基础映像视为独立的独立映像,该映像应在组织中的各种映像之间共享。因此,我认为在这种情况下这样做是不合常规的,并且如果仅是想节省存储空间(和网络带宽)的一个想法,那么这个技巧很可能是不必要的。请继续阅读。

期望这些图像要小得多

不。正如我所解释的,无论如何,您都将创建相同大小的250MB映像。它包括基本映像的大小,其中包括共享库。运行docker images时,本地Docker引擎将显示图像大小为250MB。但是正如我所说,这并不意味着您每次构建新映像时,Docker引擎都会占用额外的250MB空间。

具有依赖性的大基础图像仅存储一次

是的,但是以FROM gcr.io/distroless/java:11开头时也是如此。只要您可以为共享库创建一个单独的共享层并保持该层的稳定(即可重现),将共享库放入另一个“基本映像”就没有任何意义。 Jib非常擅长可重复地构建这样的层。保存在注册表中的位的粒度是层而不是图像,因此,实际上无需“标记”库层位于某个“基本映像”中(只要您为库创建自己的层)。注册中心仅看到层,并且仅通过声明“此图像由A层,B层和C层以及此元数据组成”来形成“图像”的概念。图像甚至没有基本图像的概念;它并没有说“此图像是通过将A层放置在此基本图像之上”。只要B层是共享库层,您的优化要比胖子层更好。

节省大量存储空间。

因此,这不是事实。毕竟,Docker引擎和注册表没有充分的理由不会多次存储同一层。

我们将其集成并使用./gradlew jibDockerBuild,它似乎确实为依赖项,资源和类创建了层次,但是仍然只有一个大的形象。

是的。图像大小为250MB。当您使用Dockerfile或任何其他图像构建工具时,情况仍然如此。但是,在使用Jib时,如果仅更改应用程序.java文件,则在重建时,Jib将通过网络仅将小型应用程序层(不包含共享库或资源)发送到远程注册表;它不会发送整个250MB的层,因为Jib保持了强大的可重复性。同样,如果仅更新共享库,Jib将仅发送库层,从而节省时间,带宽和存储空间。

但是请注意,由于Docker引擎API的功能有限,Jib无法检查Docker引擎中是否已经存储了某些层,因此在使用{{1时,Jib必须加载整个250MB的层}}。这通常不是问题,因为加载是在本地完成的,而无需通过网络。但是由于API的限制,令人惊讶的是,对于Jib而言,将映像直接推送到远程注册表通常比本地Docker引擎更快。 Jib仅需要发送已更改的图层。但是,正如我多次强调的那样,即使Jib(或任何其他图像构建工具)将整个250MB的层加载到Docker引擎中,该引擎也只会保存必要的内容(即,它从未见过的新层-还是这样)。它不会复制基本映像或共享库层;只有新的不同层会占用存储空间。并且使用jibDockerBuild,即使由于可重复性差而实际上并不是新的,您通常也会最终生成“新层”。

本文链接:https://www.f2er.com/2628972.html

大家都在问