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