建立 GraalVM Docker 映像
一、簡介
GraalVM 使用其預先 (AOT) 編譯器將 Java 應用程式編譯為機器可執行檔。這些可執行檔直接在目標電腦中執行,無需使用即時 (JIT) 編譯器。 GraalVM 產生的二進位檔案較小,啟動時間較快,且無需任何預熱即可提供峰值效能。此外,這些可執行檔案比在 JVM 上執行的應用程式具有更低的記憶體佔用和 CPU 。
Docker 允許我們將軟體元件打包到 Docker 映像中並作為 Docker 容器運行。 Docker 容器包含應用程式運作所需的一切,包括應用程式程式碼、執行時間、系統工具和程式庫。
在本教程中,我們將討論建立 Java 應用程式的 GraalVM 本機映像。然後我們將討論如何使用此本機映像作為 Docker 映像並將其作為 Docker 容器運行。
2. 什麼是原生鏡像
Native Image 是一種將 Java 程式碼提前編譯為本機可執行檔的技術。此本機可執行檔僅包含需要在執行時執行的程式碼。這包括應用程式類別、標準函式庫類別、語言執行時間和來自 JDK 的靜態連結本機程式碼。
本機映像產生器 ( native-image
) 掃描應用程式類別和其他元資料以建立特定於作業系統和體系結構的二進位檔案。 native-image
工具執行靜態應用程式程式碼分析,以確定應用程式運行時可存取的類別和方法。然後它將所需的類別、方法和資源編譯為二進位可執行檔。
3. 原生鏡像的好處
本機映像可執行檔有幾個優點:
- 由於本機映像產生器僅編譯執行時間所需的資源,因此可執行檔的大小很小。
- 本機可執行檔具有極快的啟動時間,因為它們直接在目標電腦中執行,無需 JIT 編譯器
- 由於僅打包所需的應用程式資源,因此提供較小的攻擊面
- 可用於打包輕量級容器映像(例如 Docker Image),以實現快速且有效率的部署
4. 建構 GraalVM 原生鏡像
在本節中,我們將為 Spring Boot 應用程式建立 GraalVM 本機映像。首先,我們需要安裝 GraalVM 並設定JAVA_HOME
環境變數。其次,使用Spring Web和 GraalVM Native Support 相依性建立一個 Spring Boot 應用程式:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.4</version>
</dependency>
我們還需要添加以下插件來支援 GraalVM:
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.27</version>
</plugin>
</plugins>
</build>
該應用程式包含一個範例休息控制器:
@RestController
class HelloController {
@GetMapping
public String hello() {
return "Hello GraalVM";
}
}
讓我們使用 Maven 命令建立本機可執行檔:
$mvn -Pnative native:compile
native-maven-plugin
建構 GraalVM 本機映像。由於 GraalVM 本機映像編譯器執行靜態程式碼分析,因此與常規 Java 應用程式編譯相比,建置時間較長。
以下是 GraalVM 編譯的輸出:
========================================================================================================================
GraalVM Native Image: Generating 'springboot-graalvm-docker' (executable)...
========================================================================================================================
<strong>[1/8] Initializing... (42.7s @ 0.15GB)</strong>
Java version: 17.0.8+9-LTS, vendor version: Oracle GraalVM 17.0.8+9.1
Graal compiler: optimization level: 2, target machine: x86-64-v3, PGO: ML-inferred
C compiler: gcc (linux, x86_64, 11.3.0)
Garbage collector: Serial GC (max heap size: 80% of RAM)
// Omitted for clarity
<strong>[2/8] Performing analysis... [******] (234.6s @ 1.39GB)</strong>
15,543 (90.25%) of 17,222 types reachable
25,854 (67.59%) of 38,251 fields reachable
84,701 (65.21%) of 129,883 methods reachable
4,906 types, 258 fields, and 4,984 methods registered for reflection
64 types, 70 fields, and 55 methods registered for JNI access
4 native libraries: dl, pthread, rt, z
[3/8] Building universe... (14.7s @ 2.03GB)
[4/8] Parsing methods... [*******] (55.6s @ 2.05GB)
[5/8] Inlining methods... [***] (4.9s @ 2.01GB)
[6/8] Compiling methods... [**********
[6/8] Compiling methods... [*******************] (385.2s @ 3.02GB)
[7/8] Layouting methods... [****] (14.0s @ 2.00GB)
[8/8] Creating image... [*****] (30.7s @ 2.72GB)
48.81MB (58.93%) for code area: 48,318 compilation units
30.92MB (37.33%) for image heap: 398,288 objects and 175 resources
3.10MB ( 3.75%) for other data
82.83MB in total
// Omitted for clarity
Finished generating 'springboot-graalvm-docker' in 13m 7s.
// Omitted for clarity
在上面的編譯輸出中,有以下幾個關鍵點:
- 編譯使用GraalVM Java編譯器來編譯應用程式
- 編譯器對類型、欄位和方法進行可達性檢查
- 接下來,它會建立本機執行並顯示可執行檔大小和編譯所需的時間
成功建置後,我們可以在目標目錄中找到可用的本機執行檔。該可執行檔可以在命令列中執行。
5. 建置 Docker 映像
在本節中,我們將為上一個步驟中產生的本機執行檔開發一個 Docker 映像。
讓我們建立以下 Dockerfile:
FROM ubuntu:jammy
COPY target/springboot-graalvm-docker /springboot-graalvm-docker
CMD ["/springboot-graalvm-docker"]
接下來,讓我們使用以下命令建立 Docker 映像:
$docker build -t springboot-graalvm-docker .
成功建置後,我們可以注意到springboot-graalvm-docker
Docker 映像可用:
$docker images | grep springboot-graalvm-docker
我們可以使用以下命令執行該映像:
$docker run -p 8080:8080 springboot-graalvm-docker
上面的指令啟動了容器,我們可以注意到Spring Boot的啟動日誌:
// Ommited for clarity
*** INFO 1 --- [ main] wscServletWebServerApplicationContext : Root WebApplicationContext: initialization <strong>completed in 14 ms</strong>
*** INFO 1 --- [ main] osbwembedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
*** INFO 1 --- [ main] cbgGraalvmDockerImageApplication : Started GraalvmDockerImageApplication in 0.043 seconds (process running for 0.046)
應用程式將在 43 毫秒內啟動。我們可以透過存取以下命令來存取 REST 端點:
$curl localhost:8080
它顯示以下輸出:
Hello GraalVM
六,結論
在本文中,我們為 GraalVM 本機可執行檔建立 Docker 映像。
我們開始討論 GraalVM 原生鏡像及其優勢。它對於需要首次啟動和低記憶體佔用的用例非常有用。接下來,我們使用 GraalVM 本機映像編譯器產生 Spring Boot 應用程式的本機執行檔。最後,我們使用本機執行檔開發了一個 Docker 映像,並使用該映像啟動了一個 Docker 容器。
該應用程式的源代碼可在 GitHub 上找到。