spring boot 2.3 開始spring-boot-maven-plugin
插件默認開啓了分層構建 jar包
或者 war包
,本文主要根據官方文檔記錄一下如何使用分層jar構建鏡像。html
spring-boot-maven-plugin
分層構建 jar 包配置 spring boot 項目繼承自 spring-boot-starter-parent
,設置 <parent>
以下:java
<!-- Inherit defaults from Spring Boot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.1</version> </parent>
繼承自 spring-boot-starter-parent
的項目有以下的默認配置:spring
spring-boot-dependencies POM
,管理公共依賴項的版本,這種依賴管理容許您在本身的 POM 中使用時省略那些依賴項的<version>
標記repackage
當在項目中引入 spring-boot-maven-plugin
插件默認就開啓了分層構建 jar包
,咱們可使用以下方式進行驗證:docker
在項目的 pom.xml 文件中添加以下插件配置:shell
<project> <modelVersion>4.0.0</modelVersion> <artifactId>getting-started</artifactId> <!-- ... --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
執行以下命令進行打包:緩存
mvn clean package
在 target 目錄下面生成對應的 jar 包,解壓 jar 包目錄結構以下:app
jar 分別在 BOOT-INF/classes
和 BOOT-INF/lib
中包含應用程序的類和依賴項。 相似地,可執行 war 包含 WEB-INF/classes
中的應用程序類和 WEB-INF/lib
和 WEB-INF/lib-provided
中的依賴項。 對於須要從 jar 或 war 的內容構建 docker 鏡像的狀況,須要分離這些目錄以便將它們寫入不一樣的層。maven
其中的 BOOT-INF/layers.idx
文件就是用來定義分層 jar 的構建順序的,層的順序很重要,由於它決定了在應用程序的一部分發生更改時,儘量將發生更改的內容放在後面,應該先添加最不可能更改的內容,而後再添加最可能更改的層,默認順序是:ide
dependencies
(用於存放不包含 snapshot 的依賴)spring-boot-loader
(用於存放類加載器)snapshot-dependencies
(用於存放包含 snapshot 的依賴)application
(用於存放應用程序的類和資源)此分層旨在根據應用程序構建之間更改的可能性來分離代碼,項目的依賴不太可能在內部版本之間常常更改,所以將其放置在單獨的層dependencies
中,以容許工具從新使用緩存中的層,應用程序代碼更可能在內部版本之間進行更改,所以將其隔離在單獨的層application
中。spring-boot
使用下面的命令查看分層jar 的目錄順序:
java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar list dependencies spring-boot-loader snapshot-dependencies application
使用下面的命令將jar包按照分層的目錄結構進行解壓以便建立分層鏡像:
java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar extract
關於 java -Djarmode=layertools -jar application.jar
官方的說明以下:
Usage: java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar Available commands: list List layers from the jar that can be extracted extract Extracts layers from the jar for image creation help Help about any command
要禁用此特性,能夠採用如下方式
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <layers> <enabled>false</enabled> </layers> </configuration> </plugin> </plugins> </build> </project>
知道了上面分層 jar 包的構建目錄以後,咱們可使用多階段來構建 docker 鏡像,Dockerfile
的內容以下:
# 指定基礎鏡像,這是多階段構建的前期階段 FROM openjdk:11-jre-slim as builder # 指定工做目錄,目錄不存在會自動建立 WORKDIR /app # 將生成的 jar 複製到容器鏡像中 COPY target/*.jar application.jar # 經過工具spring-boot-jarmode-layertools從application.jar中提取拆分後的構建結果 RUN java -Djarmode=layertools -jar application.jar extract # 正式構建鏡像 FROM openjdk:11-jre-slim # 指定工做目錄,目錄不存在會自動建立 WORKDIR /app # 前一階段從jar中提取除了多個文件,這裏分別執行COPY命令複製到鏡像空間中,每次COPY都是一個layer COPY --from=builder app/dependencies ./ COPY --from=builder app/spring-boot-loader ./ COPY --from=builder app/snapshot-dependencies ./ COPY --from=builder app/application ./ # 指定時區 ENV TZ="Asia/Shanghai" RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 定義一些環境變量,方便環境變量傳參 ENV JVM_OPTS="" ENV JAVA_OPTS="" # 指定暴露的端口,起到說明的做用,不指定也會暴露對應端口 EXPOSE 8080 # 啓動 jar 的命令 ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]
使用下面的命令構建 docker 鏡像:
docker build -t demo:1.0.0 .
使用以下命令查看鏡像的分層信息:
docker history demo:1.0.0
如上圖,整個 jar 的內容,例如 class、依賴庫、依賴資源等,分屢次 COPY 到鏡像空間中,因此之後若是隻改了class,在更新鏡像的時候,只須要下載 class 的 layer 便可(其餘 layer 能夠直接用以前緩存到本地的)。
參考文章: