SpringBoot項(xiàng)目docker分層鏡像構(gòu)建案例
摘要:本文主要介紹Spring Boot項(xiàng)目的docker鏡像分層構(gòu)建,分為外部依賴和內(nèi)部依賴和項(xiàng)目classes依賴,讓docker構(gòu)建的時候,可以使用之前的緩存,加快構(gòu)建速度和測試環(huán)境鏡像拉取速度。
為什么使用分層 Docker 鏡像?
傳統(tǒng)的 Docker 鏡像構(gòu)建方式會將整個應(yīng)用程序 JAR/WAR 文件復(fù)制到一個層中。當(dāng)你修改代碼時,整個層都會失效,導(dǎo)致 Docker 必須重新構(gòu)建整個應(yīng)用程序?qū)?,即使只是做了微小的代碼更改。
通過我們的分層方法,我們將以下內(nèi)容分離:
- 外部依賴(第三方庫)
- 內(nèi)部依賴(公司特定庫)
- 應(yīng)用程序代碼(實(shí)際業(yè)務(wù)邏輯)
這樣,當(dāng)你修改代碼時,只需要重新構(gòu)建應(yīng)用程序代碼層,而依賴層可以從緩存中重用。
Maven 插件配置詳解
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-external-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib/external</outputDirectory>
<includeScope>compile</includeScope>
<excludeGroupIds>cn.hutool</excludeGroupIds>
</configuration>
</execution>
<execution>
<id>copy-internal-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib/internal</outputDirectory>
<includeScope>compile</includeScope>
<includeGroupIds>cn.hutool</includeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
<encoding>UTF-8</encoding>
<!-- 如果使用預(yù)覽特性 -->
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
工作原理
1. Maven 依賴分離插件配置詳解
我們的 pom.xml 使用 maven-dependency-plugin 在構(gòu)建過程中分離依賴。該插件包含兩個執(zhí)行配置:
外部依賴復(fù)制配置
<execution>
<id>copy-external-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib/external</outputDirectory>
<includeScope>compile</includeScope>
<excludeGroupIds>cn.hutool</excludeGroupIds>
</configuration>
</execution>
配置參數(shù)說明:
<id>: 執(zhí)行的唯一標(biāo)識符
<phase>: 綁定到 Maven 生命周期的 package 階段
<goals>: 執(zhí)行的目標(biāo)是 copy-dependencies
<configuration>: 配置詳情
<outputDirectory>: 輸出目錄,${project.build.directory}是 target 目錄<includeScope>: 包含作用域?yàn)?compile 的依賴<excludeGroupIds>: 排除 groupId 為 cn.hutool 的依賴(將其視為內(nèi)部依賴)
內(nèi)部依賴復(fù)制配置
<execution>
<id>copy-internal-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib/internal</outputDirectory>
<includeScope>compile</includeScope>
<includeGroupIds>cn.hutool</includeGroupIds>
</configuration>
</execution>
配置參數(shù)說明:
<id>: 執(zhí)行的唯一標(biāo)識符
<phase>: 同樣綁定到 Maven 生命周期的 package 階段
<goals>: 執(zhí)行的目標(biāo)也是 copy-dependencies
<configuration>: 配置詳情
<outputDirectory>: 輸出目錄為 target/lib/internal<includeScope>: 包含作用域?yàn)?compile 的依賴<includeGroupIds>: 只包含 groupId 為 cn.hutool 的依賴(作為內(nèi)部依賴處理)
通過這兩個執(zhí)行配置,Maven 會在 package 階段自動將依賴分別復(fù)制到對應(yīng)的目錄中:
target/lib/external/- 第三方依賴(排除了 cn.hutool)target/lib/internal/- 內(nèi)部/公司特定依賴(只有 cn.hutool)target/classes/- 編譯后的應(yīng)用程序代碼
2. 分層 Dockerfile 詳解
我們的 Dockerfile 通過首先復(fù)制依賴來利用 Docker 層緩存:
FROM eclipse-temurin:21-jre-alpine WORKDIR /app # 1. 復(fù)制外部依賴(很少更改) COPY target/lib/external/*.jar ./lib/external/ # 2. 復(fù)制內(nèi)部依賴(偶爾更改) COPY target/lib/internal/*.jar ./lib/internal/ # 3. 復(fù)制應(yīng)用程序類(經(jīng)常更改) COPY target/classes ./classes EXPOSE 8080 ENV CUSTOM_OPTS="-Xms256m -Xmx768m" ENV JAVA_OPTS="--enable-preview -XX:+UseSerialGC" ENTRYPOINT ["sh", "-c", "java $CUSTOM_OPTS $JAVA_OPTS -cp /app/classes:/app/lib/external/*:/app/lib/internal/* com.example.layer.Sp3LayerApplication"]
Dockerfile 配置說明:
FROM eclipse-temurin:21-jre-alpine: 使用輕量級的 Alpine Linux 上的 Temurin JDK 21 運(yùn)行時環(huán)境
WORKDIR /app: 設(shè)置工作目錄為 /app
COPY target/lib/external/*.jar ./lib/external/: 將外部依賴復(fù)制到鏡像中,這是最穩(wěn)定的層
COPY target/lib/internal/*.jar ./lib/internal/: 將內(nèi)部依賴復(fù)制到鏡像中,這層比外部依賴更可能變化
COPY target/classes ./classes: 將應(yīng)用程序類文件復(fù)制到鏡像中,這層最容易發(fā)生變化
EXPOSE 8080: 暴露應(yīng)用程序端口
ENV 指令設(shè)置 JVM 參數(shù):
CUSTOM_OPTS: 自定義 JVM 參數(shù),設(shè)置初始堆內(nèi)存和最大堆內(nèi)存JAVA_OPTS: Java 虛擬機(jī)選項(xiàng),啟用預(yù)覽特性和使用串行垃圾收集器
ENTRYPOINT: 定義容器啟動時執(zhí)行的命令,使用類路徑包含所有依賴和應(yīng)用程序類
類路徑說明:
-cp /app/classes:/app/lib/external/*:/app/lib/internal/* 指定了類路徑的順序:
- /app/classes: 應(yīng)用程序編譯后的類文件優(yōu)先級最高
- /app/lib/external/*: 外部依賴次之
- /app/lib/internal/*: 內(nèi)部依賴最后
這種順序確保了應(yīng)用程序類可以覆蓋依賴中的同名類(如果需要的話),并且保證了正確的類加載順序。
3. 構(gòu)建過程詳解
Maven 構(gòu)建生命周期集成
當(dāng)執(zhí)行 mvn package 命令時,Maven 會按照以下順序執(zhí)行構(gòu)建階段:
- validate - 驗(yàn)證項(xiàng)目正確性
- compile - 編譯源代碼
- test - 運(yùn)行測試
- package - 打包應(yīng)用程序
在 package 階段,maven-dependency-plugin 會自動執(zhí)行我們配置的兩個依賴復(fù)制任務(wù):
- 首先執(zhí)行 copy-external-dependencies,將外部依賴復(fù)制到 target/lib/external/
- 然后執(zhí)行 copy-internal-dependencies,將內(nèi)部依賴復(fù)制到 target/lib/internal/
- 同時,Maven 默認(rèn)會將編譯后的類文件放在 target/classes/ 目錄中
完整構(gòu)建步驟
清理并打包應(yīng)用程序:
mvn clean package
此命令會觸發(fā)依賴分離過程,生成三個目錄:
target/classes/- 應(yīng)用程序編譯后的類文件target/lib/external/- 外部依賴 JAR 文件target/lib/internal/- 內(nèi)部依賴 JAR 文件
- 構(gòu)建 Docker 鏡像:
docker build -t sp3-layer .
Docker 構(gòu)建過程會按順序創(chuàng)建四個層:
- 基礎(chǔ)鏡像層(eclipse-temurin:21-jre-alpine)
- 外部依賴層(COPY target/lib/external/*.jar)
- 內(nèi)部依賴層(COPY target/lib/internal/*.jar)
- 應(yīng)用程序類層(COPY target/classes)
構(gòu)建優(yōu)化效果
由于 Docker 的層緩存機(jī)制:
- 當(dāng)只修改應(yīng)用程序代碼時,只有最后一層需要重建
- 當(dāng)添加新的外部依賴時,需要重建外部依賴層及其后的所有層
- 當(dāng)添加新的內(nèi)部依賴時,需要重建內(nèi)部依賴層和應(yīng)用程序類層
- 只有基礎(chǔ)鏡像變更時,才需要完全重建
優(yōu)勢
- 更快的構(gòu)建速度:代碼更改時只需重新構(gòu)建應(yīng)用程序代碼層
- 更小的傳輸量:推送到注冊中心時,只傳輸更改的層
- 更好的緩存效果:依賴層在各個構(gòu)建之間緩存并重用
- 減少帶寬消耗:在 CI/CD 流水線中減少數(shù)據(jù)傳輸
版本更新工作流程
- 在應(yīng)用程序中進(jìn)行代碼更改
- 運(yùn)行
mvn clean package僅重新編譯更改的代碼 - 運(yùn)行
docker build -t sp3-layer:v2 .構(gòu)建新鏡像 - 只有
target/classes層會被重新構(gòu)建 - 只將更改的層推送到容器注冊中心
配置自定義指南
要將此配置應(yīng)用于其他項(xiàng)目,您需要根據(jù)項(xiàng)目的依賴結(jié)構(gòu)調(diào)整配置:
修改依賴分組
如果您有不同的內(nèi)部依賴,需要修改 excludeGroupIds 和 includeGroupIds 配置:
<!-- 外部依賴配置 --> <excludeGroupIds>com.yourcompany,org.another.internal.group</excludeGroupIds> <!-- 內(nèi)部依賴配置 --> <includeGroupIds>com.yourcompany,org.another.internal.group</includeGroupIds>
最佳實(shí)踐
- 順序很重要:首先復(fù)制不經(jīng)常更改的層
- 最小化層數(shù):只分離實(shí)際在不同頻率下更改的內(nèi)容
- 多階段構(gòu)建:考慮與多階段構(gòu)建結(jié)合使用以獲得更小的最終鏡像
- 緩存失效:了解 Docker 的層緩存機(jī)制以最大化收益
這種方法可以顯著減少 CI/CD 流水線中的構(gòu)建時間,并在部署更新時最小化網(wǎng)絡(luò)傳輸。
到此這篇關(guān)于SpringBoot項(xiàng)目docker分層鏡像構(gòu)建案例的文章就介紹到這了,更多相關(guān)SpringBoot docker分層鏡像 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot用JdbcTemplates訪問Mysql實(shí)例代碼
本篇文章主要介紹了SpringBoot用JdbcTemplates訪問Mysql實(shí)例代碼,非常具有實(shí)用價值,需要的朋友可以參考下2017-05-05
java實(shí)現(xiàn)jdbc查詢結(jié)果集result轉(zhuǎn)換成對應(yīng)list集合
本文給大家匯總介紹了java實(shí)現(xiàn)jdbc查詢結(jié)果集result轉(zhuǎn)換成對應(yīng)list集合,十分的簡單,有相同需求的小伙伴可以參考下。2015-12-12
Springboot如何使用OSHI獲取和操作系統(tǒng)和硬件信息
這篇文章主要介紹了Springboot如何使用OSHI獲取和操作系統(tǒng)和硬件信息問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
springboot結(jié)合redis實(shí)現(xiàn)搜索欄熱搜功能及文字過濾
本文主要介紹了springboot結(jié)合redis實(shí)現(xiàn)搜索欄熱搜功能及文字過濾,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02

