通過Spring Boot重用Docker層

1.簡介

Docker是用於創建自包含應用程序的事實上的標準。從2.3.0版開始,Spring Boot包括多項增強功能,可幫助我們創建高效的Docker映像。因此,它允許將應用程序分解為不同的層

換句話說,源代碼駐留在其自己的層中。因此,它可以獨立重建,從而提高了效率和啟動時間。在本教程中,我們將看到如何利用Spring Boot的新功能來重用Docker層。

2. Docker中的分層罐

Docker容器由基本映像和附加層組成。構建圖層後,它們將保持緩存狀態。因此,後代將更快:

通過Spring

下層的更改也會重建上層的更改。因此,不經常變化的層應該保留在底部,而經常變化的層應該放置在頂部。

以同樣的方式,Spring Boot允許將工件的內容映射到層中。讓我們看一下默認的圖層映射:

通過Spring

如我們所見,應用程序具有其自己的層。修改源代碼時,僅重建獨立層。加載程序和依賴項將保留在緩存中,從而減少了Docker映像的創建和啟動時間。讓我們看看如何用Spring Boot做到這一點!

3.使用Spring Boot創建高效的Docker映像

在傳統的構建Docker映像的方式中,Spring Boot使用fat jar方法。結果,單個工件嵌入了所有依賴項和應用程序源代碼。因此,源代碼中的任何更改都將強制重建整個層。

3.1。使用Spring Boot進行層配置

Spring Boot版本2.3.0引入了兩個新功能,以改善Docker映像的生成:

  • Buildpack支持為應用程序提供了Java運行時,因此現在可以跳過Dockerfile並自動構建Docker映像
  • 分層jar可幫助我們充分利用Docker層生成

在本教程中,我們將擴展分層jar方法。

最初,我們將在Maven中設置分層的jar。打包工件時,我們將生成圖層。讓我們檢查一下jar文件:

jar tf target/spring-boot-docker-0.0.1-SNAPSHOT.jar

如我們所見,在胖罐子內的BOOT-INF文件夾中創建了.idx當然,它將依賴關係,資源和應用程序源代碼映射到獨立的層:

BOOT-INF/layers.idx

同樣,文件的內容分解了存儲的不同層:

- "dependencies":

    - "BOOT-INF/lib/"

 - "spring-boot-loader":

    - "org/"

 - "snapshot-dependencies":

 - "application":

    - "BOOT-INF/classes/"

    - "BOOT-INF/classpath.idx"

    - "BOOT-INF/layers.idx"

    - "META-INF/"

3.2。與圖層互動

讓我們列出工件內部的層:

java -Djarmode=layertools -jar target/docker-spring-boot-0.0.1.jar list

layers.idx文件內容的簡單視圖:

dependencies

 spring-boot-loader

 snapshot-dependencies

 application

我們還可以將圖層提取到文件夾中:

java -Djarmode=layertools -jar target/docker-spring-boot-0.0.1.jar extract

然後,我們可以重用Dockerfile內的文件夾,如我們在下一部分中將看到的:

$ ls

 application/

 snapshot-dependencies/

 dependencies/

 spring-boot-loader/

3.3。 Dockerfile配置

為了充分利用Docker功能,我們需要在圖像中添加各層。

首先,讓我們將胖子jar文件添加到基本映像中:

FROM adoptopenjdk:11-jre-hotspot as builder

 ARG JAR_FILE=target/*.jar

 COPY ${JAR_FILE} application.jar

其次,讓我們提取工件的各層:

RUN java -Djarmode=layertools -jar application.jar extract

最後,讓我們複製提取的文件夾以添加相應的Docker層:

FROM adoptopenjdk:11-jre-hotspot

 COPY --from=builder dependencies/ ./

 COPY --from=builder snapshot-dependencies/ ./

 COPY --from=builder spring-boot-loader/ ./

 COPY --from=builder application/ ./

 ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

通過這種配置,當我們更改源代碼時,我們將僅重建應用程序層。其餘的將保留在緩存中。

4.自定義層

似乎一切都像魅力一樣運作。但是,如果仔細看,依賴關係層不會在內部版本之間共享。就是說,所有這些都進入了一個單一的層,甚至是內部層。因此,如果更改內部庫的類,則將再次重建所有依賴關係層。

4.1。使用Spring Boot的自定義層配置

在Spring Boot中,可以通過單獨的配置文件來調整自定義圖層:

<layers xmlns="http://www.springframework.org/schema/boot/layers"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://www.springframework.org/schema/boot/layers

 https://www.springframework.org/schema/boot/layers/layers-2.3.xsd">

 <application>

 <into layer="spring-boot-loader">

 <include>org/springframework/boot/loader/**</include>

 </into>

 <into layer="application" />

 </application>

 <dependencies>

 <into layer="snapshot-dependencies">

 <include>*:*:*SNAPSHOT</include>

 </into>

 <into layer="dependencies" />

 </dependencies>

 <layerOrder>

 <layer>dependencies</layer>

 <layer>spring-boot-loader</layer>

 <layer>snapshot-dependencies</layer>

 <layer>application</layer>

 </layerOrder>

 </layers>

如我們所見,我們正在將依賴關係和資源映射並排序到層中。此外,我們可以根據需要添加任意數量的自定義圖層。

讓我們將文件layers.xml 。然後,在Maven中,我們可以配置此文件以自定義圖層:

<plugin>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-maven-plugin</artifactId>

 <configuration>

 <layers>

 <enabled>true</enabled>

 <configuration>${project.basedir}/src/layers.xml</configuration>

 </layers>

 </configuration>

 </plugin>

如果我們打包工件,結果將類似於默認行為。

4.2。添加新層

讓我們創建一個內部依賴項,添加我們的應用程序類:

<into layer="internal-dependencies">

 <include>com.baeldung.docker:*:*</include>

 </into>

此外,我們將訂購新層:

<layerOrder>

 <layer>internal-dependencies</layer>

 </layerOrder>

結果,如果我們列出胖子罐中的各層,則會出現新的內部依賴項:

dependencies

 spring-boot-loader

 internal-dependencies

 snapshot-dependencies

 application

4.3。 Dockerfile配置

提取後,我們可以將新的內部層添加到我們的Docker映像中:

COPY --from=builder internal-dependencies/ ./

因此,如果我們生成圖像,我們將看到Docker如何將內部依賴項作為新層構建:

$ mvn package

 $ docker build -f src/main/docker/Dockerfile . --tag spring-docker-demo

 ....

 Step 8/11 : COPY --from=builder internal-dependencies/ ./

 ---> 0e138e074118

 .....

之後,我們可以在歷史記錄中檢查Docker映像中各層的組成:

$ docker history --format "{{.ID}} {{.CreatedBy}} {{.Size}}" spring-docker-demo

 c0d77f6af917 /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B

 762598a32eb7 /bin/sh -c #(nop) COPY dir:a87b8823d5125bcc4… 7.42kB

 80a00930350f /bin/sh -c #(nop) COPY dir:3875f37b8a0ed7494… 0B

 0e138e074118 /bin/sh -c #(nop) COPY dir:db6f791338cb4f209… 2.35kB

 e079ad66e67b /bin/sh -c #(nop) COPY dir:92a8a991992e9a488… 235kB

 77a9401bd813 /bin/sh -c #(nop) COPY dir:f0bcb2a510eef53a7… 16.4MB

 2eb37d403188 /bin/sh -c #(nop) ENV JAVA_HOME=/opt/java/o… 0B

如我們所見,該層現在包括項目的內部依賴項。

5.結論

在本教程中,我們展示瞭如何生成有效的Docker映像。簡而言之,我們使用了新的Spring Boot功能來創建分層的jar。對於簡單的項目,我們可以使用默認配置。我們還展示了一種更高級的配置以重用這些層。