本文參考文檔本文使用 Maven 進行配置,Gradle 可以參考下面文檔
- Spring Boot 容器鏡像
- Spring Boot Maven 插件參考指南
- Spring Boot Gradle 插件參考指南
一、場景
最常見的是容器鏡像,将依賴、代碼、配置分層後可以利用容器鏡像層緩存機制加快建構和下載下傳,這個場景使用分層是最優最簡單的。
k8s 移除 Docker 後,文檔中的 Docker 都去掉了…現在也把常說的 Docker 鏡像 改成了 容器鏡像
二、分層配置
如果不需要自定義分層,這一步可以跳過
在項目根目錄中添加 layers.xml 配置檔案,檔案内容如下:
<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.6.xsd">
<application>
<into layer="spring-boot-loader">
<include>org/springframework/boot/loader/**</include>
</into>
<into layer="application"/>
</application>
<dependencies>
<into layer="application">
<includeModuleDependencies/>
</into>
<into layer="snapshot-dependencies">
<include>*:*:*SNAPSHOT</include>
</into>
<into layer="sencond-dependencies">
<include>com.example:*:*</include>
</into>
<into layer="dependencies"/>
</dependencies>
<layerOrder>
<layer>dependencies</layer>
<layer>spring-boot-loader</layer>
<layer>sencond-dependencies</layer>
<layer>snapshot-dependencies</layer>
<layer>application</layer>
</layerOrder>
</layers>
和官方示例相比這裡增加了 sencond-dependencies,算是二方庫依賴,如果公司有自己架構,自己平台,根據依賴的穩定性(修改頻率)進行更細的分層。
依賴分層設計,可以參考 企業 Maven 依賴管理層次結構設計。
使用 IDEA,并且下載下傳 layers-2.6.xsd 的情況下,
<includeModuleDependencies/>
會報紅,如下圖所示:

通過檢視官方文檔和 spring boot 代碼,發現文檔、代碼和 xsd 定義存在不一緻的地方,提了 issues#31115 、 pr#31117、pr#31126 ,代碼已經合并, xsd經過修改,和文檔保持一緻。
增加上面的配置後,修改插件使用該配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<layers>
<enabled>true</enabled>
<configuration>${project.basedir}/layers.xml</configuration>
</layers>
</configuration>
</plugin>
三、容器鏡像
建構鏡像有多種方式,官方文檔介紹了 Dockerfile 和 Buildpacks 兩種。
3.1 Dockerfile
通過
layertools
可以将 fat jar 按照分層定義中的層進行解壓,指令如下:
Usage:
java -Djarmode=layertools -jar my-app.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
通過
java -Djarmode=layertools -jar my-app.jar extract
即可解壓 jar 包到目前目錄。為了友善,可以直接通過 Dockerfile 的多階段建構進行,Dockerfile 如下:
FROM eclipse-temurin:11-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM eclipse-temurin:11-jre
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
如果有自定義分層,記得按順序加入到 COPY 部分
一般情況下 target 下面隻有一個 jar 字尾的包,此時可以直接執行下面的 Docker 指令:
docker build --tag imageName:version .
如果有多個 jar,需要通過參數指定:
docker build --build-arg JAR_FILE=path/to/myapp.jar --tag imageName:version .
建構後檢視鏡像資訊:
IMAGE CREATED CREATED BY SIZE COMMENT
e1d22f48893d 11 seconds ago ENTRYPOINT ["java" "org.springframework.boot… 0B buildkit.dockerfile.v0
<missing> 11 seconds ago COPY application/application/ ./ # buildkit 55.1kB buildkit.dockerfile.v0
<missing> 11 seconds ago COPY application/snapshot-dependencies/ ./ #… 46.1MB buildkit.dockerfile.v0
<missing> 12 seconds ago COPY application/spring-boot-loader/ ./ # bu… 252kB buildkit.dockerfile.v0
<missing> 12 seconds ago COPY application/dependencies/ ./ # buildkit 216MB buildkit.dockerfile.v0
<missing> 10 minutes ago WORKDIR /application 0B buildkit.dockerfile.v0
<missing> 2 months ago /bin/sh -c set -eux; arch="$(dpkg --print-… 210MB
<missing> 2 months ago /bin/sh -c #(nop) ENV JAVA_VERSION=8u322 0B
<missing> 2 months ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 2 months ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 2 months ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 2 months ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 2 months ago /bin/sh -c set -eux; apt-get update; apt-g… 4.88MB
<missing> 2 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 months ago /bin/sh -c #(nop) ADD file:d48a85028743f16ed… 80.4MB
層資訊:
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:1401df2b50d5de5a743b7bac3238ef3b7ce905ae39f54707b0ebb8eda3ab10bc",
"sha256:43015d7c36457e91ff0994082e7016335d5aa7690e8b5c799d41c2bab47f086c",
"sha256:f1bceed991c5891bd4bf3ad6e1ade5334e2c40ada40305b59fbf0a275ebbed17",
"sha256:7a49a2f5a65e2f57886dd32ffe85542283b249ccefd7a1b5379632030912d804",
"sha256:8791c93670dee0e973efce4424ea9b33caa49e7ef15c8e0bde1912b51c349524",
"sha256:94c6796cee53f42ae2478affbfc8510c97c76e65015ec46309f83265df078ef8",
"sha256:033be8a54968fe881ce71510862eacc0c3f3bdb6eb2af1a9130704bbe7442ae8",
"sha256:ab0700832472168ad4a9060b3fbedf8cc44f22ff1d074aebb67d9ee466796515",
"sha256:06a62903d01189112c0c8b6b68debaa170228e9d7cf868e1b9959001e877a4c4"
]
}
對代碼進行簡單修改後,重新建構鏡像,再次檢視:
IMAGE CREATED CREATED BY SIZE COMMENT
cc399ec3ba61 13 seconds ago ENTRYPOINT ["java" "org.springframework.boot… 0B buildkit.dockerfile.v0
<missing> 13 seconds ago COPY application/application/ ./ # buildkit 52.9kB buildkit.dockerfile.v0
<missing> 3 minutes ago COPY application/snapshot-dependencies/ ./ #… 46.1MB buildkit.dockerfile.v0
<missing> 3 minutes ago COPY application/spring-boot-loader/ ./ # bu… 252kB buildkit.dockerfile.v0
<missing> 3 minutes ago COPY application/dependencies/ ./ # buildkit 216MB buildkit.dockerfile.v0
<missing> 13 minutes ago WORKDIR /application 0B buildkit.dockerfile.v0
<missing> 2 months ago /bin/sh -c set -eux; arch="$(dpkg --print-… 210MB
<missing> 2 months ago /bin/sh -c #(nop) ENV JAVA_VERSION=8u322 0B
<missing> 2 months ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 2 months ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 2 months ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 2 months ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 2 months ago /bin/sh -c set -eux; apt-get update; apt-g… 4.88MB
<missing> 2 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 months ago /bin/sh -c #(nop) ADD file:d48a85028743f16ed… 80.4MB
層資訊:
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:1401df2b50d5de5a743b7bac3238ef3b7ce905ae39f54707b0ebb8eda3ab10bc",
"sha256:43015d7c36457e91ff0994082e7016335d5aa7690e8b5c799d41c2bab47f086c",
"sha256:f1bceed991c5891bd4bf3ad6e1ade5334e2c40ada40305b59fbf0a275ebbed17",
"sha256:7a49a2f5a65e2f57886dd32ffe85542283b249ccefd7a1b5379632030912d804",
"sha256:8791c93670dee0e973efce4424ea9b33caa49e7ef15c8e0bde1912b51c349524",
"sha256:94c6796cee53f42ae2478affbfc8510c97c76e65015ec46309f83265df078ef8",
"sha256:033be8a54968fe881ce71510862eacc0c3f3bdb6eb2af1a9130704bbe7442ae8",
"sha256:ab0700832472168ad4a9060b3fbedf8cc44f22ff1d074aebb67d9ee466796515",
"sha256:4c0f187537195a34793722097d719f0c1247fec1648a6bdcf08f42556348af74"
]
}
和上面相比隻有最上面的一層不同,通過分層盡可能利用Docker層緩存,可以減小鏡像的差異,使得鏡像更新時,隻需要下載下傳有差異的這一小部分。
建構鏡像後,我們通過 grype 檢測鏡像是否存在安全漏洞:
$ grype 鏡像名:版本
✔ Vulnerability DB [no update available]
✔ Loaded image
✔ Parsed image
✔ Cataloged packages [521 packages]
✔ Scanned image [136 vulnerabilities]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
apt 2.2.4 deb CVE-2011-3374 Negligible
aviator 3.3.0 java-archive GHSA-xpv2-8ppj-79hh Critical
bsdutils 1:2.36.1-8+deb11u1 deb CVE-2022-0563 Negligible
coreutils 8.32-4+b1 deb CVE-2017-18018 Negligible
coreutils 8.32-4+b1 (won't fix) deb CVE-2016-2781 Low
e2fsprogs 1.46.2-2 (won't fix) deb CVE-2022-1304 High
gzip 1.10-4 1.10-4+deb11u1 deb CVE-2022-1271 Unknown
libapt-pkg6.0 2.2.4 deb CVE-2011-3374 Negligible
...
還可以對代碼進行檢查(
dir:.
目前目錄):
$ grype dir:.
✔ Vulnerability DB [no update available]
✔ Indexed .
✔ Cataloged packages [378 packages]
✔ Scanned image [36 vulnerabilities]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
aviator 3.3.0 java-archive GHSA-xpv2-8ppj-79hh Critical
maven-aether-provider 3.1.1 java-archive CVE-2021-26291 Critical
maven-artifact 3.1.1 java-archive CVE-2021-26291 Critical
maven-common-artifact-filters 3.2.0 java-archive CVE-2021-26291 Critical
maven-core 3.1.1 java-archive CVE-2021-26291 Critical
maven-model 3.1.1 java-archive CVE-2021-26291 Critical
maven-model-builder 3.1.1 java-archive CVE-2021-26291 Critical
maven-repository-metadata 3.1.1 java-archive CVE-2021-26291 Critical
maven-settings 3.1.1 java-archive CVE-2021-26291 Critical
maven-settings-builder 3.1.1 java-archive CVE-2021-26291 Critical
maven-shared-utils 3.3.3 java-archive CVE-2021-26291 Critical
minio 8.3.8 java-archive CVE-2021-21390 Medium
minio 8.3.8 java-archive CVE-2020-11012 High
minio 8.3.8 java-archive CVE-2021-21287 High
3.2 Buildpacks
Spring Boot 插件內建了 Buildpacks 功能,插件配置如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
執行
mvn org.springframework.boot:spring-boot-maven-plugin:build-image
即可建構鏡像。
建構完鏡像後,運作時可能會遇到中文亂碼,可以通過下面兩種方式解決:
1 運作鏡像時,通過環境變量指定編碼:
docker run -e JAVA_OPTS="-Dfile.encoding=UTF-8" <image_name>
2 配置 spring boot 插件,添加預設的 JVM 配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
<configuration>
<image>
<env>
<BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS>
<BPE_APPEND_JAVA_TOOL_OPTIONS>-Dfile.encoding=UTF-8</BPE_APPEND_JAVA_TOOL_OPTIONS>
</env>
</image>
</configuration>
</plugin>
環境變量配置規則文檔
https://github.com/paketo-buildpacks/environment-variables 上面兩個ENV配置介紹如下:
- 追加分隔符使用空格,xml配置保留白格(
)。
xml:space="preserve"
- 追加JVM參數
四、Jar 包運作
java org.springframework.boot.loader.JarLauncher