Optimizing docker packaging speed of spring boot application

Jiedao jdon 2021-05-04 15:49:36
optimizing docker packaging speed spring

Focus on how to use a faster method for iterative development and deployment Spring Boot Application build Docker Mirror image ? That is to speed up the construction of images , Reduce the waiting time .

Docker Concept

Docker There are four key concepts : Mirror image , Layers ,Dockerfile and Docker cache .

1. Dockerfile Describes how to build a mirror .

2. The mirror consists of many layers .

3. Dockerfile Start with the basic image and add other layers .

4. When you add new content to the image, a new layer is generated .

5. Every layer built is cached , So it can be reused in subsequent builds .

6. When Docker Build runtime , It can use any existing layer in the cache , This reduces the total time and space required for each build , Anything that has been changed or not previously built will be rebuilt again .

Layer content

This is where layers play an important role . Only if the content of the layer has not changed , Can be used Docker Existing layers in the cache .Docker If more layers are changed during the build ,Docker The more work it takes to rebuild the image .

Layer order is also important . Reuse layers only if all parent layers remain unchanged , It's better to put more frequently changed layers behind , So that changes to them affect fewer sub layers .

The order and content of the layers are important . Package the application as Docker Mirror image , The easiest way is to push the entire application to a single tier . however , If the application contains many static library dependencies when changing the minimum amount of code , You need to rebuild the entire layer . It's going to end up in Docker A lot of build time and space are wasted in caching .

Layers affect deployment

Deploy Docker Mirror image , Layers are also important . In the deployment Docker Before the mirror , They will be pushed to remote Docker The repository , This repository acts as the source for all deployment images , And usually contains many versions of the same image .

Docker Very efficient , Only one layer of storage , however , For images that are frequently deployed and have the ability to continuously rebuild large layers , This efficiency is useless . Large layers , Even if the internal changes are small , It must also be stored separately in the repository and pushed across the network , This has a negative impact on deployment time , Because you need to move and store duplicate bits for unchanging parts bit.

Docker Medium Spring Boot application

Use super jar The packaging method is Spring Boot The application is a separate deployment unit . This model is very suitable for deployment on virtual machines or build packages , Because applications can carry everything they need with them .

however , This is for Docker Deployment is a drawback :Docker A way to package dependencies has been provided . Will the whole Spring Boot JAR Put in Docker Mirror images are very common . however , This can lead to Docker There are too many invariant bits in the mirrored application layer bit.

Spring The community is talking about how to run Spring Boot Reduce the size and time of deployment when applying , Especially in Docker in .

This is ultimately a trade-off between simplicity and efficiency . by Spring Boot Application building Docker The most common method of mirroring is what I call “ monolayer ” Method . This is not technically correct , Because actually Dockerfile Created multiple layers , But it's enough for the purpose of this discussion .

Single layer method

Let's take a look at the monolayer method . The monolayer method is fast , direct , Easy to understand and use .Docker Of Spring Boot The guide lists single-layer Dockerfile To build Docker Mirror image :

FROM openjdk:8-jdk-alpine
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

The end result is a working Docker Mirror image , It works the way you expect it to Spring Boot The way the application works is exactly the same . however , It is plagued by the problem of hierarchical efficiency , Because it's based on the whole application JAR, As the application source changes , Whole Spring Boot JAR Will rebuild , Next build Docker Mirror image , The entire application layer will be rebuilt , Include all unchanged library dependencies .

Learn more about the monolayer approach

The monolayer method uses Spring Boot JAR structure Docker Mirror image , be based on Open JDK On the basis of the mirror image Docker The layers are as follows :

$ docker images
springio/spring-petclinic latest 94b0366d5ba2 16 seconds ago

Generated Docker Mirror as 140 MB. You can use this docker history Command to check layers . You can see Spring Boot Applications JAR Copied to size 38.3 MB In the image of .

$ docker history springio/spring-petclinic

Next time you build Docker Mirror image , Will recreate the entire 38 MB layer , because JAR The file has been repackaged .

In this example , The application size is relatively small , Based on spring-boot-starter-web Other dependencies , for example spring-actuator. In the real world , These are usually larger sizes , Because they don't just include Spring Boot library , There are also other third-party libraries . According to my experience , Actually Spring Boot The size of the application can range from 50 MB To 250 MB( If not bigger ).

Take a close look at the application , There are only... In the application code 372 KB Applications for JAR. remainder 38 MB Is a library dependency . This means that only 0.1% The layers are actually changing . rest 99.9% Unchanged .

Layer life cycle

This illustrates the basic consideration of layering : The life cycle of content . Layers and content should have the same lifecycle .Spring Boot The content of an application has two different lifecycles : Library dependencies that change infrequently and application classes that change frequently .

Every time a layer is rebuilt due to a change in application code , It also includes invariant binaries . In a fast application development environment where application code is constantly changing and re deployed , This additional cost can become very expensive .

Imagine , An application team in Pet Clinic Iterate on the . The team changes and redeploys the application every day 10 Time . this 10 The cost of each new layer will be per day 383 MB. Use more real sizes , Up to... Every day 2.5 GB Or more . This is ultimately a waste of build time , Deployment time and Docker Repository space .

Fast 、 Progressive development and delivery is when trade-offs become important , It is necessary to continue to use simple single-layer methods or more effective alternatives .

hug Docker,Go Dual Layer

In the trade-off between simplicity and efficiency , I think the right choice is “ double ” Method .( More layers may , But too many layers can be harmful , And in violation of Docker Best practices ). In the two-layer method , We build Docker Mirror image , In order to Spring Boot The library dependencies of an application exist in the layers below the application code . such , Layers follow different lifecycles of content . By pushing infrequently changed library dependencies to a separate tier and leaving only the application classes at the top level , Iterative reconstruction and redeployment will be faster .

A two-tier approach speeds up iterative development , And minimize deployment time . The results vary by application , But on average , This will reduce the application deployment size 90%, At the same time, the deployment cycle time is reduced accordingly .

We need a way to Spring Boot The application is split into these separate components :

springBootUtility yes Open Liberty A new tool in , It will Spring Boot The application is divided into two parts : Kuilei , for example Spring Boot Starters and other third-party libraries , And application code . Library dependencies are placed in the library cache , Application code is used to build streamlined applications . The thin application contains a file , This file refers to the required library on the classpath . You can then deploy this thin application to Open Liberty, It will generate the full classpath from the library cache .

To build this double-layer image Dockerfile Build... In multiple phases . Multistage construction allows a single Dockerfile Create multiple images , The contents of one image can be copied to another image , Discard temporary content . This allows you to dramatically reduce the size of the final mirror , It doesn't have to involve multiple Docker file . We use this function in Docker Split during build Spring Boot Applications .

Docker Mirror usage Open JDK And Open J9 and Open Liberty.Open JDK Open source Java Technology provides a solid foundation .Open J9 Than Open JDK Attached default Java Virtual machines bring some performance improvements .Open Liberty It's a multi programming model runtime , Support Java EE,MicroProfile and Spring. This allows the development team to use various programming models with a consistent runtime stack .


FROM adoptopenjdk/openjdk8-openj9 as staging
# Install unzip; needed to unzip Open Liberty
RUN apt-get update \
&& apt-get install -y --no-install-recommends unzip \
&& rm -rf /var/lib/apt/lists/*
# Install Open Liberty
ENV LIBERTY_SHA 4170e609e1e4189e75a57bcc0e65a972e9c9ef6e
ENV LIBERTY_URL https://public.dhe.ibm.com/ibmdl/export/pub/software/openliberty/runtime/release/2018-06-19_0502/openliberty-
RUN curl -sL "$LIBERTY_URL" -o /tmp/wlp.zip \
&& echo "$LIBERTY_SHA /tmp/wlp.zip" > /tmp/wlp.zip.sha1 \
&& sha1sum -c /tmp/wlp.zip.sha1 \
&& mkdir /opt/ol \
&& unzip -q /tmp/wlp.zip -d /opt/ol \
&& rm /tmp/wlp.zip \
&& rm /tmp/wlp.zip.sha1 \
&& mkdir -p /opt/ol/wlp/usr/servers/springServer/ \
&& echo spring.boot.version="$SPRING_BOOT_VERSION" > /opt/ol/wlp/usr/servers/springServer/bootstrap.properties \
&& echo \
'<?xml version="1.0" encoding="UTF-8"?> \
<server description="Spring Boot Server"> \
<featureManager> \
<feature>jsp-2.3</feature> \
<feature>transportSecurity-1.0</feature> \
<feature>websocket-1.1</feature> \
<feature>springBoot-${spring.boot.version}</feature> \
</featureManager> \
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" httpsPort="9443" /> \
<include location="appconfig.xml"/> \
</server>' > /opt/ol/wlp/usr/servers/springServer/server.xml \
&& /opt/ol/wlp/bin/server start springServer \
&& /opt/ol/wlp/bin/server stop springServer \
&& echo \
'<?xml version="1.0" encoding="UTF-8"?> \
<server description="Spring Boot application config"> \
<springBootApplication location="app" name="Spring Boot application" /> \
</server>' > /opt/ol/wlp/usr/servers/springServer/appconfig.xml
# Stage the fat JAR
COPY ${JAR_FILE} /staging/myFatApp.jar
# Thin the fat application; stage the thin app output and the library cache
RUN /opt/ol/wlp/bin/springBootUtility thin \
--sourceAppPath=/staging/myFatApp.jar \
--targetThinAppPath=/staging/myThinApp.jar \
# unzip thin app to avoid cache changes for new JAR
RUN mkdir /staging/myThinApp \
&& unzip -q /staging/myThinApp.jar -d /staging/myThinApp
# Final stage, only copying the liberty installation (includes primed caches)
# and the lib.index.cache and thin application
FROM adoptopenjdk/openjdk8-openj9
# Create the individual layers
COPY --from=staging /opt/ol/wlp /opt/ol/wlp
COPY --from=staging /staging/lib.index.cache /opt/ol/wlp/usr/shared/resources/lib.index.cache
COPY --from=staging /staging/myThinApp /opt/ol/wlp/usr/servers/springServer/apps/app
# Start the app on port 9080
CMD ["/opt/ol/wlp/bin/server", "run", "springServer"]

Use Docker The multi-stage construction and implementation of the springBootUtilityOpen Liberty,Dockerfile Division Spring Boot Applications :

Let's start with a temporary image . First , We installed unzip. Next , We download it in some configurations Open Liberty and stage. All these preparations need to be ready Open Liberty Tools . We know it's very ugly , This is our announcement in the near future Liberty Docker One of the things that mirror improves .

Once the mirror has all the tools it needs ,JAR The file will be copied to the staging image and split . After creating the thin application below /staging/myFatApp.jar, Further optimization steps will be taken to decompress it . This decompression causes the application to be hosted directly from the class file . If the class file has not changed , This allows reuse of the application layer for subsequent rebuilds .

Now? , The segmentation work has been completed , Let's start over , So that we can copy the final Liberty install , Dependency libraries and thin applications .Dockerfile Alone in COPY The command generates separate layers . The larger kuilai layer (34.2MB) And smaller application layers (1.01MB) yes ' double ' The meaning of .

$ docker history openlibertyio / spring-petclinic

Now? , When making application changes , Just change the application layer .

Optimizing Spring Boot apps for Docker - OpenLiber

[ The quilt banq On 2018-09-25 15:05 A modified ]

本文为[Jiedao jdon]所创,转载请带上原文链接,感谢

  1. Realization of reactor Kafka through spring boot Webflux
  2. RPC框架设计----Socket与I/0模型
  3. Problems in upgrading from Java 8 to Java 11
  4. RPC framework design -- socket and I / 0 model
  5. RPC框架设计----I/0模型
  6. RPC framework design: I / 0 model
  7. RPC框架设计----NIO编程缓冲区Buffer
  8. RPC框架设计----NIO编程缓冲区Buffer
  9. RPC framework design -- NiO programming buffer
  10. RPC framework design -- NiO programming buffer
  11. Java多线程基础
  12. Java multithreading Foundation
  13. 码农飞升记-00-Java发展历程
  14. Development history of coder-00-java
  15. 码农飞升记-00-Java发展历程
  16. Development history of coder-00-java
  17. Spring and Autumn Moon
  18. Node.js与Spring Boot比较? - Ryan Gleason
  19. Spring WebFlux的明显陷阱 - ŁukaszKyć
  20. Spring创始人Rod大叔对YAML的真实想法
  21. Compare node.js with spring boot- Ryan Gleason
  22. Obvious pitfalls of spring Webflux- Ł ukaszKy ć
  23. Spring founder uncle rod's real thoughts on yaml
  24. 码农飞升记-02-OracleJDK是什么?OracleJDK的版本怎么选择?
  25. What is manong feisheng-02-oracle JDK? How to choose the version of Oracle JDK?
  26. Spring tide surging Xinanjiang
  27. Linux内核软中断
  28. Linux kernel soft interrupt
  29. Linux内核软中断
  30. Linux kernel soft interrupt
  31. Java multithreading Foundation
  32. The construction of Maven private library nexus
  33. I / O stream in Java
  34. JDK 16:Java 16的新功能 - InfoWorld
  35. 在Java中本地进行线程间数据传输的三种方式和源码展示
  36. jdon导致cpu 99%最后tomcat死掉---banq给予回复
  37. 用领域事件模拟AOP注入
  38. JDK 16: new function of Java 16 - InfoWorld
  39. Cartoon: from JVM lock to redis distributed lock
  40. Spring 3.1 终于加入了Cache支持
  41. Prototype与JQuery对比
  42. Three ways of data transmission between threads in Java and source code display
  43. Jdon causes 99% of CPU and Tomcat dies -- banq replies
  44. docker 原理之 user namespace(下)
  45. Simulating AOP injection with domain events
  46. Spring 3.1 finally adds cache support
  47. Comparison between prototype and jquery
  48. User namespace of docker principle (2)
  49. The way to learn java IO stream and XML
  50. Why does a seemingly correct code cause the Dubbo thread pool to be full
  51. 0 基础 Java 自学之路(2021年最新版)
  52. 0 basic Java self study road (latest version in 2021)
  53. c#—基础拾遗(1) 面向对象
  54. C - basic information (1) object oriented
  55. 技术分享|SQL和 NoSQL数据库之间的差异:MySQL(VS)MongoDB
  56. Technology sharing differences between SQL and NoSQL databases: MySQL (VS) mongodb
  57. PHP教程/面向对象-3~构造函数和析构函数
  58. Spring Cloud的Feign客户端入门
  59. 优化Spring Boot应用的Docker打包速度
  60. PHP tutorial / object oriented - 3 ~ constructor and destructor