300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Spring Boot 容器镜像分层构建

Spring Boot 容器镜像分层构建

时间:2023-06-01 17:22:51

相关推荐

Spring Boot 容器镜像分层构建

本文参考文档

Spring Boot 容器镜像Spring Boot Maven 插件参考指南

本文使用 Maven 进行配置,Gradle 可以参考下面文档

Spring Boot Gradle 插件参考指南

一、场景

最常见的是容器镜像,将依赖、代码、配置分层后可以利用容器镜像层缓存机制加快构建和下载,这个场景使用分层是最优最简单的。

k8s 移除 Docker 后,文档中的 Docker 都去掉了…现在也把常说的Docker 镜像改成了容器镜像

二、分层配置

如果不需要自定义分层,这一步可以跳过

在项目根目录中添加layers.xml配置文件,文件内容如下:

<layers xmlns="/schema/boot/layers"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/schema/boot/layers/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.jarAvailable commands:listList layers from the jar that can be extractedextract Extracts layers from the jar for image creationhelpHelp about any command

通过java -Djarmode=layertools -jar my-app.jar extract即可解压 jar 包到当前目录。为了方便,可以直接通过 Dockerfile 的多阶段构建进行,Dockerfile 如下:

FROM eclipse-temurin:11-jre as builderWORKDIR applicationARG JAR_FILE=target/*.jarCOPY ${JAR_FILE} application.jarRUN java -Djarmode=layertools -jar application.jar extractFROM eclipse-temurin:11-jreWORKDIR applicationCOPY --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 .

构建后查看镜像信息:

IMAGECREATEDCREATED BY SIZECOMMENTe1d22f48893d 11 seconds ago ENTRYPOINT ["java" "org.springframework.boot… 0B buildkit.dockerfile.v0<missing>11 seconds ago COPY application/application/ ./ # buildkit55.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… 252kBbuildkit.dockerfile.v0<missing>12 seconds ago COPY application/dependencies/ ./ # buildkit 216MBbuildkit.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"]}

对代码进行简单修改后,重新构建镜像,再次查看:

IMAGECREATEDCREATED BY SIZECOMMENTcc399ec3ba61 13 seconds ago ENTRYPOINT ["java" "org.springframework.boot… 0B buildkit.dockerfile.v0<missing>13 seconds ago COPY application/application/ ./ # buildkit52.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… 252kBbuildkit.dockerfile.v0<missing>3 minutes ago COPY application/dependencies/ ./ # buildkit 216MBbuildkit.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 TYPEVULNERABILITY SEVERITY apt 2.2.4deb CVE--3374 Negligible aviator 3.3.0java-archive GHSA-xpv2-8ppj-79hh Critical bsdutils 1:2.36.1-8+deb11u1 deb CVE--0563 Negligible coreutils 8.32-4+b1deb CVE--18018 Negligible coreutils 8.32-4+b1 (won't fix) deb CVE--2781 Low e2fsprogs 1.46.2-2 (won't fix) deb CVE--1304 High gzip 1.10-4 1.10-4+deb11u1 deb CVE--1271 Unknownlibapt-pkg6.0 2.2.4deb CVE--3374 Negligible ...

还可以对代码进行检查(dir:.当前目录):

$ grype dir:. ✔ Vulnerability DB [no update available]✔ Indexed .✔ Cataloged packages[378 packages]✔ Scanned image [36 vulnerabilities]NAME INSTALLEDFIXED-INTYPEVULNERABILITY SEVERITY aviator 3.3.0 java-archive GHSA-xpv2-8ppj-79hh Critical maven-aether-provider3.1.1 java-archive CVE--26291 Critical maven-artifact 3.1.1 java-archive CVE--26291 Critical maven-common-artifact-filters 3.2.0 java-archive CVE--26291 Critical maven-core 3.1.1 java-archive CVE--26291 Critical maven-model3.1.1 java-archive CVE--26291 Critical maven-model-builder 3.1.1 java-archive CVE--26291 Critical maven-repository-metadata3.1.1 java-archive CVE--26291 Critical maven-settings 3.1.1 java-archive CVE--26291 Critical maven-settings-builder 3.1.1 java-archive CVE--26291 Critical maven-shared-utils 3.3.3 java-archive CVE--26291 Critical minio8.3.8 java-archive CVE--21390 Medium minio8.3.8 java-archive CVE--11012 Highminio8.3.8 java-archive CVE--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>

环境变量配置规则文档

/paketo-buildpacks/environment-variables

上面两个ENV配置介绍如下:

追加分隔符使用空格,xml配置保留空格(xml:space="preserve")。追加JVM参数

四、Jar 包运行

除了使用镜像外,当使用 Jar 包运行时,通过jar xf xxxx.jar可以解压 jar 包到当前目录,解压后通过下面命令启动:

java org.springframework.boot.loader.JarLauncher

通过这种方式运行时,可以相对方便的修改配置文件,可以替换更新某些 jar 依赖,不用在对整个 fat jar 进行操作。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。