基於Spring Boot 2.3以上版本方便建立分層Docker映象

banq發表於2020-01-28

Spring Boot 2.3.0.M1剛剛釋出,它帶來了一些有趣的新功能,可以幫助您將Spring Boot應用程式打包到Docker映象中。在此部落格文章中,我們將介紹開發人員建立Docker映象的典型方式,並展示如何使用這些新功能進行改進。

普通Docker技術:

建立一個類似以下內容的dockerfile:

FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/my-application.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

儘管這種方法很好用,簡潔明瞭,但是有些事情不是最理想的。

Spring Boot 2.3.0.M1中引入了兩個新功能,以幫助改進這些現有技術:buildpack支援和分層jar。

buildpack

Spring Boot 2.3.0.M1直接支援Maven和Gradle的buildpack。這意味著您只需鍵入一個命令,即可將明智的映像快速獲取到本地執行的Docker守護程式中。對於Maven,您可以mvn spring-boot:build-image使用Gradle 鍵入gradle bootBuildImage。釋出映象的名稱將是您的應用程式名稱,標籤將是版本。

讓我們看一下使用Maven的示例:

首先使用start.spring.io建立一個新的Spring Boot專案:

$ curl https://start.spring.io/starter.zip -d bootVersion=2.3.0.M1 -d dependencies=web -o demo.zip
$ unzip demo.zip

下一步在本地機器上安裝Docker並執行,然後:

$ ./mvnw spring-boot:build-image

第一次執行將花費一些時間,但後續呼叫會更快。

您的應用程式已編譯,打包並轉換為Docker映像。您可以使用以下方法進行測試:

$ docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT

Spring Boot提供的內建支援提供了一種開始使用buildpack的好方法。由於它是buildpack平臺規範的實現,因此也很容易遷移到功能更強大的buildpack工具,例如packkpack確信會生成相同的映像。

分層jar

Spring Boot始終支援其自己的“胖jar”格式,該格式允許您建立可以使用java -jar執行。如果您曾經研究過該jar的內容,則會看到一個類似以下的結構:

META-INF / 
  MANIFEST.MF 
org / 
  springframework / 
    boot / 
      loader / 
        ... 
BOOT-INF / 
  classes / 
    ... 
  lib / 
    ...

分為三個主要部分:

  • classes是用於引導jar載入的類
  • Spring Boot應用程式類是在 BOOT-INF/classes
  • 依賴是在 BOOT-INF/lib

由於這種格式是Spring Boot特有的,因此我們有可能以有趣的方式進行發展。藉助Spring Boot,2.3.0.M1我們提供了layout一種稱為的新型別LAYERED_JAR。

如果您選擇採用分層格式並檢視jar結構,則會看到以下內容:

META-INF/
  MANIFEST.MF
org/
  springframework/
    boot/
      loader/
        ...
BOOT-INF/
  layers/
    <name>/
      classes/
        ...
      lib/
        ...
    <name>/
      classes/
        ...
      lib/
        ...
  layers.idx

現在lib和classes資料夾已拆分並分類為圖層。還有一個新layers.idx檔案,提供了新增圖層的順序。

最初,我們提供了以下現成的圖層:

  • dependencies (對於常規釋出的依賴項)
  • snapshot-dependencies (對於快照依賴性)
  • resources (用於靜態資源)
  • application (用於應用程式類和資源)

此分層旨在根據應用程式構建之間更改的可能性來分離程式碼。庫程式碼不太可能在內部版本之間進行更改,因此將其放置在自己的層中,以允許工具重新使用快取中的層。應用程式程式碼更可能在內部版本之間進行更改,因此將其隔離在單獨的層中。

提取圖層

jarmode是啟動jar時可以設定的特殊系統屬性。它允許引導程式碼執行與您的應用程式完全不同的內容。例如,提取圖層。

編寫dockerfile

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layout>LAYERED_JAR</layout>
            </configuration>
        </plugin>
    </plugins>
</build>

然後重新構建Jar:

mvn clean package

現在應該有一個帶有jarmode支援的分層jar 。使用以下命令進行測試:

$ java -Djarmode=layertools -jar target/demo-0.0.1-SNAPSHOT.jar list

應該看到以下輸出,該輸出告訴我們應新增的圖層及其順序:

dependencies
snapshot-dependencies
resources
application

可以製作一個dockerfile用於提取並複製每個圖層的檔案。這是一個例子:

ROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk:11-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/resources/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

這是一個多階段的dockerfile。該builder階段提取以後需要的資料夾。每個COPY命令都與我們前面列出的層有關。

要構建映象,我們可以執行:

$ docker build . --tag demo

測試:

$ docker run -it -p8080:8080 demo:latest

總結

使用buildpacks,dockerfiles和現有外掛(例如jib),這些都是建立Docker映象的方法。每種方法都有其優點和缺點,但是希望無論您選擇哪種方法,我們在Spring Boot 2.3中提供的新功能都將有所幫助。

 

相關文章