优化Docker中的Spring Boot应用:单层镜像方法

栏目: IT技术 · 发布时间: 5年前

内容简介:文介绍了如何使用Docker中的一些关键概念和结构组件来优化Spring Boot应用程序。Docker功能强大且易于使用。Docker允许开发人员研制的软件创建可移植的镜像。这些镜像可重复地部署。你可以很容易地从Docker中获得很多价值,但是要从Docker中获得最大的价值,需要理解一些概念。在进行持续集成和持续交付时,如何构建Docker镜像具有重要的作用。在本文中,我将重点介绍:

优化 <a href='https://www.codercto.com/topics/20577.html'>Docker</a> 中的Spring Boot应用:单层镜像方法

文介绍了如何使用Docker中的一些关键概念和结构组件来优化Spring Boot应用程序。

Docker功能强大且易于使用。Docker允许开发人员研制的软件创建可移植的镜像。这些镜像可重复地部署。你可以很容易地从Docker中获得很多价值,但是要从Docker中获得最大的价值,需要理解一些概念。在进行持续集成和持续交付时,如何构建Docker镜像具有重要的作用。在本文中,我将重点介绍:

  • 在进行迭代开发和部署时,如何采用更有效的方法为Spring Boot应用程序构建Docker镜像。
  • 为Spring Boot应用程序构建Docker镜像的标准方法有一些缺点,因此在这里我们要介绍如何做得更好。

Docker关键概念

Docker有四个关键概念:images, layers, Dockerfile 和 Docker cache 。简而言之,Dockerfile描述了如何构建Docker镜像。镜像由许多层组成。Dockerfile从基础镜像开始,并添加了其他层。当新内容添加到镜像时,将生成一个新层。所构建的每个层都被缓存,因此可以在后续构建中重复使用。当Docker构建运行时,它可以从缓存中获取重复使用任何已有层。这就减少了每次构建所需的时间和空间。任何已更改或以前尚未构建的内容都将根据需要进行构建。

优化Docker中的Spring Boot应用:单层镜像方法

Docker更新频率

镜像层内容很重要

镜像各层的重要性。Docker缓存中的现有层,只有当改镜像层内容没有变更时,才能被使用。在Docker构建期间更改的层越多,Docker需要执行更多的工作来重建镜像。镜像层顺序也很重要。如果某个图层的所有父图层均未更改,则该图层就能被重用。因此,最好把比较频繁更改的图层放在上面,以便对其更改会影响较少的子图层。镜像层的顺序和内容很重要。当你把应用程序打包为Docker镜像时,最简单的方法是将整个应用程序放置到一个单独的镜像层中。但是,如果该应用程序包含大量静态库依赖,那么即使更改很少的代码,也需要重新构建整个镜像层。这就需要在Docker缓存中,花费大量构建时间和空间。

镜像层影响部署

部署Docker镜像时,镜像层也很重要。在部署Docker镜像之前,它们会被推送到Docker远程仓库。该仓库是所有部署镜像的源头,并且经常包含同一镜像的许多版本。Docker非常高效,每个层仅存储一次。但是,对于频繁部署且具有不断重建的大体积层的镜像,这就不行了。大体积层的镜像,即使内部只有很少的更改,也必须单独存储在仓库中并在网络中推送。因为需要移动并存储不变的内容,这就会增加部署时间,

Docker中的Spring Boot应用

使用uber-jar方法的Spring Boot应用程序本身就是独立的部署单元。该模型非常适合在虚拟机或构建包上进行部署,因为该应用程序可带来所需的一切。但是,这对Docker部署是一个缺点:Docker已经提供了打包依赖项的方法。将整个Spring Boot JAR放入Docker镜像是很常见的,但是,这会导致Docker镜像的应用程序层中的不变内容太多。

优化Docker中的Spring Boot应用:单层镜像方法

Java SpringBoot单层

Spring社区中正在进行有关减少运行Spring Boot应用程序时的部署大小和时间的讨论,尤其是在Docker中。在我看来,这最终是在简单性与效率之间进行权衡。为Spring Boot应用程序构建Docker镜像的最常见方法是我所说的“单层”方法。从技术上讲,这不是正确的,因为Dockerfile实际上创建了多个层,但是对于讨论来说已经足够了。

单层方法

让我们看一下单层方法。单层方法快速,简单,易于理解和使用。Docker的Spring Boot指南 列出了单层Dockerfile来构建你的Docker镜像:

FROM openjdk:8-jdk-alpine 
VOLUME /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 Boot JDK基础镜像之上的Spring Boot JAR作为Docker层构建Docker镜像:

$ docker images 
REPOSITORY                    TAG         IMAGE ID            CREATED             SIZE 
springio/spring-petclinic     latest      94b0366d5ba2        16 seconds ago      140MB 

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

$ docker history springio/spring-petclinic 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT 
94b0366d5ba2        52 seconds ago      /bin/sh -c #(nop)  ENTRYPOINT ["java" "-Djav…   0B 
213dff56a4bd        53 seconds ago      /bin/sh -c #(nop) COPY file:d3551559c2aa35af…   38.3MB 
bc453a32748e        6 minutes ago       /bin/sh -c #(nop)  ARG JAR_FILE                 0B 
7fe0bb0d8026        6 minutes ago       /bin/sh -c #(nop)  VOLUME [/tmp]                0B 
cc2179b8f042        8 days ago          /bin/sh -c set -x  && apk add --no-cache   o…   97.4MB 
<missing>           8 days ago          /bin/sh -c #(nop)  ENV JAVA_ALPINE_VERSION=8…   0B 
<missing>           8 days ago          /bin/sh -c #(nop)  ENV JAVA_VERSION=8u151       0B 
<missing>           8 days ago          /bin/sh -c #(nop)  ENV PATH=/usr/local/sbin:…   0B 
<missing>           8 days ago          /bin/sh -c #(nop)  ENV JAVA_HOME=/usr/lib/jv…   0B 
<missing>           8 days ago          /bin/sh -c {   echo '#!/bin/sh';   echo 'set…   87B 
<missing>           8 days ago          /bin/sh -c #(nop)  ENV LANG=C.UTF-8             0B 
<missing>           5 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B 
<missing>           5 months ago        /bin/sh -c #(nop) ADD file: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仓库空间。快速迭代的开发和交付是决定我们是继续使用简单的单层方法,还是采用更有效的替代方法。

拥抱Docker,进入双层

在简单性和效率之间进行权衡时,我认为正确的选择是“双层”方法。(可以有更多的层,但是太多的层可能有害,并且违反了 Docker最佳实践)。在双层方法中,我们构建Docker镜像,以使Spring Boot应用程序的依赖库,存在于应用程序代码下方的一层中。这样,各层将遵循内容的不同生命周期。通过将不经常更改的依赖库推入一个单独的层,并仅将应用程序类保留在顶层,那么迭代重建和重新部署就会更快。

优化Docker中的Spring Boot应用:单层镜像方法

Java Spring Boot双层

双层方法加快了迭代开发的速度,并最大程度地缩短了部署时间。当然实际效率因应用程序而异,但是平均而言,这将使应用程序部署大小减少90%,同时相应地缩短了部署周期。

在本系列的下一篇文章“ 为Spring Boot应用程序创建双层Docker镜像”中,我将介绍如何在Open Liberty项目中使用新 工具 为Spring Boot应用程序构建双层Docker镜像。

译者:王延飞原文链接:https://dzone.com/articles/optimizing-spring-boot-application-for-docker


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Haskell

Haskell

Simon Thompson / Addison-Wesley / 1999-3-16 / GBP 40.99

The second edition of Haskell: The Craft of Functional Programming is essential reading for beginners to functional programming and newcomers to the Haskell programming language. The emphasis is on th......一起来看看 《Haskell》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具