隨著越來越多的組織轉向容器和虛擬服務器,Docker正成為軟體開發作業流程中一個更重要的部分,為此,Spring Boot 2.3中最新的功能之中,提供了為Spring Boot應用程式創建 Docker 鏡像的能力,
這篇文章的目的,就是為了給大家介紹如何為 Spring Boot 應用程式創建 Docker 鏡像,
1. 傳統Docker構建
使用Spring Boot 構建 Docker 鏡像的傳統方法是使用 Dockerfile ,下面是一個簡單的例子:
FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/demo-app-1.0.0.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
然后我們可以使用 docker build 命令來創建 Docker 映像,這對大多數應用程式都很好,但也有一些缺點,
首先,我們使用的是 Spring Boot 創建的 fat jar,這會影響啟動時間,尤其是在集裝箱環境中,我們可以通過添加jar檔案的分解內容來節省啟動時間,
其次,Docker鏡像是分層構建的,Spring Boot fat jar 的特性使得所有的應用程式代碼和第三方庫都放在一個層中,這意味著即使只有一行代碼更改,也必須重新構建整個層,
通過在構建之前分解 jar ,應用程式代碼和第三方庫各自獲得自己的層,這樣,我們便可以利用Docker的快取機制,現在,當某一行代碼被更改時,只需要重新構建相應的層,
考慮到這一點,讓我們看看Spring Boot 如何改進創建Docker鏡像的程序,
2. Buildpacks
BuildPacks 是一種提供框架和應用程式依賴性的工具,
例如,給定一個Spring Boot fat jar,一個buildpack將為我們提供Java運行時,這使我們可以跳過 Dockerfile 并自動獲得一個合理的docker 鏡像,
Spring Boot 包括對 bulidpacks 的Maven和Gradle支持,例如,使用Maven構建時,我們將運行以下命令:
./mvnw spring-boot:build-image
我們觀察下一些相關的輸出,看看發生了什么:
[INFO] Building jar: target/demo-0.0.1-SNAPSHOT.jar
...
[INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100%
...
[INFO] [creator] ===> DETECTING
[INFO] [creator] 5 of 15 buildpacks participating
[INFO] [creator] paketo-buildpacks/bellsoft-liberica 2.8.1
[INFO] [creator] paketo-buildpacks/executable-jar 1.2.8
[INFO] [creator] paketo-buildpacks/apache-tomcat 1.3.1
[INFO] [creator] paketo-buildpacks/dist-zip 1.3.6
[INFO] [creator] paketo-buildpacks/spring-boot 1.9.1
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] Total time: 44.796 s
第一行顯示我們構建了標準的 fat jar,與其他典型的maven包一樣,
下一行開始Docker映像構建,然后,看到這個 bulid 拉取了 packeto 構建器,
packeto 是基于云原生 bulidpacks 的實作,它負責分析我們的專案并確定所需的框架和庫,在我們的例子中,它確定我們有一個Spring Boot專案并添加所需的構建包,
最后,我們看到生成的Docker映像和總構建時間,注意,在第一次構建時,花了相當多的時間下載構建包并創建不同的層,
buildpacks 的一大特點是Docker映像是多層的,因此,如果我們只更改應用程式代碼,后續構建將更快:
...
[INFO] [creator] Reusing layer 'paketo-buildpacks/executable-jar:class-path'
[INFO] [creator] Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] Total time: 10.591 s
3. 層級jar包
在某些情況下,我們可能不喜歡使用 bulidpacks ——也許我們的基礎架構已經系結到另一個工具上,或者我們已經有了我們想要重新使用的自定義 Dockerfiles ,
基于這些原因,Spring Boot 還支持使用分層jars 構建Docker映像,為了了解它的作業原理,讓我們看看一個典型的Spring Boot fat jar 布局:
org/
springframework/
boot/
loader/
...
BOOT-INF/
classes/
...
lib/
...
fat jar 由3個主要區域組成:
- 啟動Spring應用程式所需的引導類
- 應用程式代碼
- 第三方庫
使用分層jar,結構看起來很相似,但是我們得到了一個新的 layers.idx 將 fat jar 中的每個目錄映射到一個層的檔案:
- "dependencies":
- "BOOT-INF/lib/"
- "spring-boot-loader":
- "org/"
- "snapshot-dependencies":
- "application":
- "BOOT-INF/classes/"
- "BOOT-INF/classpath.idx"
- "BOOT-INF/layers.idx"
- "META-INF/"
Out-of-the-box, Spring Boot provides four layers:
開箱即用,Spring Boot 提供4層:
- dependencies: 來自第三方的依賴
- snapshot-dependencies: 來自第三方的 snapshot 依賴
- resources: 靜態資源
- application: 應用程式代碼和資源(resources)
我們的目標是將應用程式代碼和第三方庫放置到層中,以反映它們更改的頻率,
例如,應用程式代碼可能是更改最頻繁的代碼,因此它有自己的層,此外,每一層都可以獨立演化,只有當一層發生變化時,才會為它重建 Docker 鏡像,
現在我們了解了分層 jar 結構,接下來看看如何利用它來制作 Docker 映像,
3.1.創建分層 jar
首先,我們必須建立一個專案來創建一個分層的jar,對于Maven,則需要在POM的 Spring Boot plugin 部分添加一個新的配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>
有了這個配置,Maven package 命令(包括它的其他依賴命令)將使用前面提到的四個默認層生成一個新的分層jar,
3.2. 查看和提取分層
下一步,我們需要從 jar 中提取層,這樣Docker鏡像才能擁有正確的層,
要檢查分層jar的任何層,可以運行以下命令:
java -Djarmode=layertools -jar demo-0.0.1.jar list
然后提取它們,運行命令:
java -Djarmode=layertools -jar demo-0.0.1.jar extract
3.3. 創建Docker映像
將這些層合并到 Docker 映像中的最簡單方法是使用 Dockerfile :
FROM adoptopenjdk:11-jre-hotspot as builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM adoptopenjdk:11-jre-hotspot
COPY --from=builder dependencies/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
這個 Dockerfile 從fat jar中提取層,然后將每個層復制到Docker映像中,
每個COPY指令最終都會在Docker映像中生成一個新層,
如果我們構建這個Dockerfile,我們可以看到分層jar中的每個層都作為自己的層添加到Docker鏡像中:
...
Step 6/10 : COPY --from=builder dependencies/ ./
---> 2c631b8f9993
Step 7/10 : COPY --from=builder snapshot-dependencies/ ./
---> 26e8ceb86b7d
Step 8/10 : COPY --from=builder spring-boot-loader/ ./
---> 6dd9eaddad7f
Step 9/10 : COPY --from=builder application/ ./
---> dc80cc00a655
...
4.總結
在本文中,我們學習了使用 Spring Boot 構建 Docker 映像的各種方法,
使用 buildpacks,我們可以獲得合適的Docker鏡像,而無需模板或自定義配置,
或者,再多花點功夫,我們就可以使用分層 jar 來獲得一個更加定制的Docker鏡像,
如果你覺得文章還不錯,記得關注公眾號: 鍋外的大佬
劉一手的博客
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/221729.html
標籤:其他
上一篇:邊緣設備、系統及計算雜談(1)
