微服務通常使用Spring Boot框架構建,並與Docker一起部署。本文探討了用於Docker化Spring Boot應用程序的兩個常見選項。在整個過程中,我們將使用一個簡單的REST應用程序作為運行示例。
本文使用Spring Tool Suite來構建應用程序,雖然只要有pom文件,IDE和應用程序都不會那麼重要。在本文中還是要假定讀者對Docker的瞭解最少,我們將討論的選擇之一不需要Docker。然後是REST控制器:
<code>package
hello;import
org.springframework.boot.SpringApplication;import
org.springframework.boot.autoconfigure.SpringBootApplication;import
org.springframework.web.bind.annotation
.RequestMapping;import
org.springframework.web.bind.annotation
.RestController;public
class
Application
{public
String home() {return
"Hello from Spring Boot in Docker"
; }public
static void main(String[] args) { SpringApplication.run(Application.
class
,args);
} }/<code>
package hello;我們將其構建到目標目錄中的fat jar中。Dockerize的最簡單方法是將fat jar填充到容器中:
Docker文件
<code>FROM
adoptopenjdk:11
-jre-hotspot ARG JAR_FILE=target/*.jar
COPY${JAR_FILE}
app.jar ENTRYPOINT ["java"
,"-jar"
,"/app.jar"
/<code>
事實證明這不是個好方法。
在這種情況下,我們的應用程序及其所有依賴項都放在了一層。如果我們不斷更改應用程序,那麼即使依賴項jar很少更改,每次也會從頭開始重建映像。這就導致了構建很緩慢。
更好的選擇是遵循舊的軟件設計原則,並從保持不變的地方區分出一些變化。我們可以通過將依賴項放在底層,將應用程序放在頂層來做到這一點。Docker隨後將緩存依賴關係層,並且每次我們更改應用程序並重建映像時,將從緩存中檢索依賴關係層,從而加快構建速度。
對於第一個選擇,我們考慮一個非常傳統的團隊,其中開發團隊和構建團隊是分開的;開發人員對Docker一無所知,也不想知道。開發團隊將構建應用程序,並將其交給構建團隊來管理構建和部署。
fat jar分為三個部分:
- 用於引導jar加載的類
- 在BOOT-INF / classes中的應用程序類
- BOOT-INF / lib中的依賴項
可以通過檢查jar文件(jar tvf app.jar)來查看。我們可以利用這一點來分離各層。當然可以提取jar文件,然後在Dockerfile中移動並複製圖層。但Spring使分層罐變得更加容易。因此,開發人員調整pom文件以啟用圖層
<code><
plugins
><
plugin
>….<
configuration
><
layers
><
enabled
>trueenabled
>layers
>configuration
>plugin
>plugins
>/<code>
開發團隊將自己構建的fat jar移交給構建團隊。
列出圖層
<code>java -Djarmode=layertools -jar app.jarlist
dependencies spring-boot-loader snapshot-dependencies application/<code>
現在,構建團隊可以提取jar文件的層並將其複製到多級docker文件中的映像層(多級docker文件是具有許多已命名構建階段的文件)
Docker文件
<code>FROM
adoptopenjdk:11-jre-hotspot as builder
WORKDIR
application
ARG
JAR_FILE=target/*.jar
COPY
${JAR_FILE} application.jar
RUN
java -Djarmode=layertools -jar application.jar extract
FROM
adoptopenjdk:11-jre-hotspot
WORKDIR
application
COPY
application/dependencies/ ./
COPY
application/spring-boot-loader/ ./
COPY
application/snapshot-dependencies/ ./
COPY
application/application/ ./
ENTRYPOINT
["java", "org.springframework.boot.loader.JarLauncher"]
/<code>
請注意,Dockerfile中沒有特定於應用程序的內容,這就是我們使用jarlauncher的原因。它將使圖像開始變慢,不過影響不大。此外,我們假設存在Docker的本地實例
我們可以照常構建圖像(將圖像稱為“示例”)
docker構建 標籤示例
<code>docker
images
REPOSITORY
TAG IMAGE ID CREATED SIZE
example
latest de7a3bb4889e 7 days ago 243MB
/<code>
現在運行它:
docker run -it -p80:8080 example:latest
並在瀏覽器中轉到localhost,然後看到“在Docker中從Spring Boot向您問好”。
第二種選擇是根據微服務原則建立更現代化的團隊。在這裡,開發團隊本身負責構建和部署Docker映像。但是開發團隊仍然對Docker一無所知。
此外先了解一下jib。
“ Jib是一個快速,簡單的容器映像生成器,它處理將應用程序打包為容器映像的所有步驟。它不需要編寫Dockerfile或安裝Docker,它可以直接集成到 Maven 和 Gradle中-只需將插件添加到構建中,就可以立即將Java應用程序容器化”
要使用Jib,我們修改pom以插入:
<code><
plugin
><
groupId
>com.google.cloud.toolsgroupId
><
artifactId
>jib-maven-pluginartifactId
><
version
>2.4.0version
><
configuration
><
to
><
image
>jibexample2image
>to
>configuration
>plugin
>/<code>
現在,對於此示例,我們假設團隊有一個正在運行 的Docker本地實例,
我們已將圖像命名為jibexample2。現在建立專案
mvn compile jib:dockerBuild
如果列出docker映像(docker映像),將會看到:
“存儲庫標記圖像ID的創建大小”
jibexample2 latest 7b84d5781eca 50 years ago 142MB
沒有Docker文件,也沒有Docker知識。注意大小。可以通過docker inspect檢查映像,並查看入口點是hello。應用程序,都可以看到列出的圖層。這些層有些不同:
- Classes
- Resources
- Project dependencies
- Snapshot dependencies
- All other dependencies
基本映像是Distroless Java。非發行版映像僅包含運行時依賴項。它們不包含程序包管理器,shell或期望在標準Linux發行版中找到的任何其他程序。每個人都可以更改基本圖像。Jib計算出ENTRYPOINT。為了進行比較,這裡是Jib隱式使用的Dockerfile。
<code>1
2
3
FROM
gcr.io/distroless/java:latest
4
5
6
7
COPY
dependencyJars
/app/libs
8
9
COPY
snapshotDependencyJars
/app/libs
10
11
COPY
projectDependencyJars
/app/libs
12
13
COPY
resources
/app/resources
14
15
COPY
classFiles
/app/classes
16
17
18
19
20
21
ENTRYPOINT
["java",
jib.container.jvmFlags,
"-cp"
,
"/app/resources:/app/classes:/app/libs/*"
,
jib.container.mainClass]
CMD
[jib.container.args]
/<code>
另外,我們可以使用jib:build代替jib:dockerBuild,如果提供了憑據,它將把映像推送到遠程註冊表。使用jib:buildTar可以將映像另存為tarball到target / jib-image.tar,你可以對其進行檢查並將其導入Docker。Jib還有許多其他配置。
關鍵字: application docker 映像