为Docker优化Spring Boot应用

Docker功能强大且易于使用。Docker允许开发人员为其创建的软件创建可移植的自包含映像。这些映像可以可靠且可重复地部署。您可以很容易地从Docker中获得很多价值,但是要从Docker中获得最大的价值,需要理解一些概念。在进行持续集成和持续交付时,如何构建Docker映像具有可观的影响。在本文中,我将重点介绍在进行迭代开发和部署时如何采用更有效的方法为Spring Boot应用程序构建Docker映像。标准方法有一些缺点,因此在这里我们看看它们是什么以及如何做得更好。

Docker关键概念
Docker发挥了四个关键概念:图像,层,Dockerfile和Docker缓存。简而言之,Dockerfile描述了如何构建Docker映像。图像由许多层组成。Dockerfile从基础映像开始,并添加了其他层。当新内容添加到图像时,将生成一个新层。所构建的每个层都被缓存,因此可以在后续构建中重复使用。当Docker构建运行时,它将重用它可以从缓存中获取的任何现有层。这减少了每个构建所需的总时间和空间。任何已更改或以前尚未构建的内容都将根据需要进行构建。
在这里插入图片描述
层内容很重要
这就是各层重要性的体现。只有当该层内容不变时,才能使用Docker缓存中的现有层。在Docker构建之间更改的层越多,Docker需要执行更多的工作来重建映像。层顺序也很重要。如果某个图层的所有父图层均未更改,则该图层只能重用。最好稍后放置更频繁更改的图层,以便对其进行更改会影响较少的子图层。

层的顺序和内容很重要。当您将应用程序打包为Docker映像时,最简单的方法是将整个应用程序推送到单个层中。但是,如果该应用程序包含大量静态库依赖项,则即使更改最少的代码,也需要重新构建整个层。最终浪费了Docker缓存中的大量构建时间和空间。
层影响部署
部署Docker映像时,层也很重要。在部署Docker映像之前,它们会被推送到远程Docker存储库。该存储库充当所有部署映像的源,并且经常包含同一映像的许多版本。Docker非常高效,每个层仅存储一次。但是,对于频繁部署且具有不断重建的大图层的映像,此效率将无法正常工作。大型层,即使内部只有很少的更改,也必须单独存储在存储库中并在网络中推送。这对部署时间有负面影响,因为需要移动并存储不变的片段的重复位。
Docker中的Spring Boot应用
使用uber-jar方法的Spring Boot应用程序本身就是独立的部署单元。该模型非常适合在虚拟机或构建包上进行部署,因为该应用程序可带来所需的一切。但是,这对Docker部署是一个缺点:Docker已经提供了打包依赖项的方法。将整个Spring Boot JAR放入Docker映像是很常见的。但是,这会导致Docker映像的应用程序层中的不变位太多。
在这里插入图片描述
Spring社区中正在进行有关减少运行Spring Boot应用程序时的部署大小和时间的讨论,尤其是在Docker中。[1] [2] [3] [4]在我看来,这最终是在简单性与效率之间进行权衡。为Spring Boot应用程序构建Docker映像的最常见方法是我所说的“单层”方法。从技术上讲,这不是正确的,因为Dockerfile实际上创建了多个层,但是对于讨论来说已经足够了。
单层方法
让我们看一下单层方法。单层方法快速,简单,易于理解和使用。Docker的Spring Boot指南列出了单层Dockerfile来构建您的Docker映像:

来自openjdk:8-jdk-alpine
音量/ tmp
ARG JAR_FILE
COPY $ {JAR_FILE} app.jar
ENTRYPOINT [“ java”,“-Djava.security.egd = file:/ dev /./ urandom”,“-jar”,“ / app.jar”]

最终结果是一个正常运行的Docker映像,其运行方式与您期望Spring Boot应用程序运行的方式完全相同。但是,由于它基于整个应用程序JAR,因此存在分层效率问题。随着应用程序源的更改,整个Spring Boot JAR都会被重建。下次构建Docker映像时,将重新构建整个应用程序层,包括所有不变的库依赖项。

让我们看一个具体的例子,在这个例子中是Spring Pet Clinic。

更深入地了解单层方法
单层方法在Open JDK基本映像之上使用Spring Boot JAR作为Docker层构建Docker映像:

$码头图片
储藏标签图像ID尺寸增加
springio / spring-petclinic最新94b0366d5ba2 16秒前140MB

生成的Docker映像为140 MB。您可以使用docker history命令检查图层。您可以看到Spring Boot应用程序JAR已复制到映像中,大小为38.3 MB。

$ docker history springio / spring-petclinic
通过尺寸注释创建的图像
94b0366d5ba2 52秒前/ bin / sh -c#(nop)ENTRYPOINT [“ java”“ -Djav…0B
213dff56a4bd 53秒前/ bin / sh -c#(nop)COPY文件:d3551559c2aa35af…38.3MB
bc453a32748e 6分钟前/ bin / sh -c#(nop)ARG JAR_FILE 0B
7fe0bb0d8026 6分钟前/ bin / sh -c#(nop)音量[/ tmp] 0B
cc2179b8f042 8天前/ bin / sh -c设置-x && apk添加--no-cache o…97.4MB
<missing> 8天前/ bin / sh -c#(nop)ENV JAVA_ALPINE_VERSION = 8…0B
<missing> 8天前/ bin / sh -c#(nop)ENV JAVA_VERSION = 8u151 0B
<missing> 8天前/ bin / sh -c#(nop)ENV PATH = / usr / local / sbin:…0B
<missing> 8天前/ bin / sh -c#(nop)ENV JAVA_HOME = / usr / lib / jv…0B
<missing> 8天前/ bin / sh -c {echo'#!/ bin / sh'; 回声设置... 87B
<missing> 8天前/ bin / sh -c#(nop)ENV LANG = C.UTF-8 0B
<missing> 5个月前/ bin / sh -c#(nop)CMD [“ / bin / sh”] 0B
<missing> 5个月前/ bin / sh -c#(nop)添加文件:093f0723fa46f6cdb…4.15MB

下次构建Docker映像时,将重新创建整个38 MB的层,因为重新打包了JAR文件。

在此示例中,应用程序的大小相对较小(仅基于spring-boot-starter-web和其他依赖项(例如spring-actuator))。在现实世界中,这些大小通常要大得多,因为它们不仅包括Spring Boot库,还包括其他第三方库。根据我的经验,实际的Spring Boot应用程序的大小范围可能在50 MB到250 MB之间(如果不是更大的话)。

仔细观察该应用程序,应用程序JAR中只有372 KB是应用程序代码。其余38 MB是库依赖关系。这意味着实际上只有0.1%的层在变化。其余99.9%不变。

层生命周期
这证明了分层的基本考虑:内容的生命周期。层的内容应具有相同的生命周期。Spring Boot应用程序的内容有两个不同的生命周期:不经常更改的库依赖关系和经常更改的应用程序类。

每次由于应用程序代码更改而重建该层时,也会包含不变的二进制文件。在快速的应用程序开发环境中,不断更改和重新部署应用程序代码,这种附加成本可能变得非常昂贵。

想象一个应用团队在Pet Clinic上进行迭代。团队每天更改和重新部署应用程序10次。这10个新层的成本为每天383 MB。如果使用更多实际大小,则每天最多可以达到2.5 GB或更多。最终浪费大量的构建时间,部署时间和Docker Repository空间。

这种快速,渐进的开发和交付是权衡重要的时刻。继续使用简单的单层方法,或者采用更有效的替代方法。
拥抱Docker,走向双层
在简单性和效率之间进行权衡,我认为正确的选择是“双层”方法。(可能有更多的层,但是太多的层可能有害,并且违反Docker最佳实践)。在双层方法中,我们构建Docker映像,以使Spring Boot应用程序的库依赖项存在于应用程序代码下方的一层中。这样,各层将遵循内容的不同生命周期。通过将不经常更改的库依赖项推入一个单独的层,并仅将应用程序类保留在顶层,则迭代重建和重新部署将更快。
在这里插入图片描述
双层方法加快了迭代开发的速度,并最大程度地缩短了部署时间。结果因应用程序而异,但是平均而言,这将使应用程序部署大小减少90%,同时相应地缩短了部署周期。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值