初めての GraalVM ネイティブアプリケーションの開発

Spring Boot ネイティブイメージアプリケーションを構築するには、主に次の 2 つのメソッドがあります。

新しいネイティブ Spring Boot プロジェクトを開始する最も簡単な方法は、start.spring.io に移動し、GraalVM Native Support 依存関係を追加してプロジェクトを生成することです。含まれている HELP.md ファイルは、開始するためのヒントを提供します。

サンプルアプリケーション

ネイティブイメージを作成するために使用できるサンプルアプリケーションが必要です。この目的には、初めての Spring Boot アプリケーションの開発セクションで説明されているシンプルな "Hello World!" Web アプリケーションで十分です。

要約すると、メインのアプリケーションコードは次のようになります。

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;

@RestController
@SpringBootApplication
public class MyApplication {

	@RequestMapping("/")
	String home() {
		return "Hello World!";
	}

	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}

}

このアプリケーションは、Spring MVC と組み込みの Tomcat を使用します。どちらも、GraalVM ネイティブイメージで動作することがテストおよび検証されています。

Buildpacks を使用したネイティブイメージの構築

Spring Boot は、MavenGradle の両方と Cloud Native Buildpacks (CNB) の統合、および Paketo Java ネイティブイメージ buildpack (英語) を使用して、ネイティブ実行可能ファイルを含む Docker イメージの構築をサポートします。つまり、コマンドを 1 つ入力するだけで、ローカルで実行されている Docker デーモンに適切なイメージをすばやく取り込むことができます。結果のイメージには JVM が含まれず、ネイティブイメージが静的にコンパイルされます。これにより、イメージのサイズが小さくなります。

イメージに使用される CNB ビルダーは paketobuildpacks/builder-jammy-tiny:latest です。フットプリントが小さく、攻撃対象領域が縮小されていますが、必要に応じて paketobuildpacks/builder-jammy-base:latest または paketobuildpacks/builder-jammy-full:latest を使用して、イメージでさらに多くのツールを利用できるようになります。

システム要件

Docker をインストールする必要があります。詳細については、Docker を入手 (英語) を参照してください。Linux を使用している場合は root 以外のユーザーを許可するように構成します (英語)

docker run hello-world (sudo なし)を実行して、Docker デーモンが期待どおりに到達可能であることを確認できます。詳細については、Maven または Gradle Spring Boot プラグインのドキュメントを確認してください。
macOS では、Docker に割り当てられたメモリを少なくとも 8GB に増やし、場合によっては CPU も追加することをお勧めします。詳細については、このスタックオーバーフローの回答 (英語) を参照してください。Microsoft Windows では、パフォーマンスを向上させるために Docker WSL2 バックエンド (英語) を有効にしてください。

Maven の使用

Maven を使用してネイティブイメージコンテナーを構築するには、pom.xml ファイルで spring-boot-starter-parent および org.graalvm.buildtools:native-maven-plugin を使用するようにする必要があります。次のような <parent> セクションが必要です。

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>3.3.1</version>
</parent>

さらに、これを <build> <plugins> セクションに含める必要があります。

<plugin>
	<groupId>org.graalvm.buildtools</groupId>
	<artifactId>native-maven-plugin</artifactId>
</plugin>

spring-boot-starter-parent は、ネイティブイメージを作成するために実行する必要がある実行を構成する native プロファイルを宣言します。コマンドラインで -P フラグを使用して、プロファイルをアクティブ化できます。

spring-boot-starter-parent を使用したくない場合は、Spring Boot のプラグインから process-aot ゴールの実行を構成し、Native Build Tools プラグインから add-reachability-metadata ゴールを構成する必要があります。

イメージをビルドするには、native プロファイルをアクティブにして spring-boot:build-image ゴールを実行します。

$ mvn -Pnative spring-boot:build-image

Gradle の使用

Spring Boot Gradle プラグインは、GraalVM Native Image プラグインが適用されると、AOT タスクを自動的に構成します。Gradle ビルドに org.graalvm.buildtools.native を含む plugins ブロックが含まれていることを確認する必要があります。

org.graalvm.buildtools.native プラグインが適用されている限り、bootBuildImage タスクは JVM ではなくネイティブイメージを生成します。以下を使用してタスクを実行できます。

$ gradle bootBuildImage

サンプルの実行

適切なビルドコマンドを実行すると、Docker イメージが利用可能になります。docker run を使用してアプリケーションを開始できます。

$ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT

次のような出力が表示されます。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v{version-spring-boot})
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)
起動時間はマシンごとに異なりますが、JVM で実行されている Spring Boot アプリケーションよりもはるかに高速です。

Web ブラウザーを localhost:8080 で開くと、次の出力が表示されるはずです。

Hello World!

アプリケーションを正常に終了するには、ctrl-c を押します。

ネイティブビルドツールを使用したネイティブイメージのビルド

Docker を使用せずにネイティブ実行可能ファイルを直接生成する場合は、GraalVM Native Build Tools を使用できます。ネイティブビルドツールは、Maven と Gradle の両方に対して GraalVM が提供するプラグインです。使用して、ネイティブイメージの生成など、さまざまな GraalVM タスクを実行できます。

前提条件

ネイティブビルドツールを使用してネイティブイメージをビルドするには、マシンに GraalVM ディストリビューションが必要です。Liberica ネイティブイメージキットページ (英語) で手動でダウンロードするか、SDKMAN! などのダウンロードマネージャーを使用できます。

Linux と macOS

macOS または Linux にネイティブイメージコンパイラーをインストールするには、SDKMAN! を使用することをお勧めします。次のコマンドを使用して、sdkman.io (英語) から SDKMAN! を取得し、Liberica GraalVM ディストリビューションをインストールします。

$ sdk install java 22.3.r17-nik
$ sdk use java 22.3.r17-nik

java -version の出力をチェックして、正しいバージョンが構成されていることを確認します。

$ java -version
openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode)

Windows

Windows では、次の手順 (英語) に従って、バージョン 22.3 の GraalVM (英語) または Liberica ネイティブイメージキット (英語) 、Visual Studio ビルドツール、および Windows SDK をインストールします。Windows 関連のコマンドラインの最大長 のため、Maven または Gradle プラグインを実行するには、通常の Windows コマンドラインではなく、必ず x64 ネイティブツールコマンドプロンプトを使用してください。

Maven の使用

buildpacks サポートと同様に、native プロファイルを継承するために spring-boot-starter-parent を使用していること、および org.graalvm.buildtools:native-maven-plugin プラグインが使用されていることを確認する必要があります。

native プロファイルがアクティブな状態で、native:compile ゴールを呼び出して native-image コンパイルをトリガーできます。

$ mvn -Pnative native:compile

ネイティブイメージの実行可能ファイルは、target ディレクトリにあります。

Gradle の使用

Native Build Tools Gradle プラグインがプロジェクトに適用されると、Spring Boot Gradle プラグインが Spring AOT エンジンを自動的にトリガーします。タスクの依存関係は自動的に構成されるため、標準の nativeCompile タスクを実行するだけでネイティブイメージを生成できます。

$ gradle nativeCompile

ネイティブイメージの実行可能ファイルは、build/native/nativeCompile ディレクトリにあります。

サンプルの実行

この時点で、アプリケーションは機能するはずです。アプリケーションを直接実行して開始できるようになりました。

  • Maven

  • Gradle

$ target/myproject
$ build/native/nativeCompile/myproject

次のような出力が表示されます。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v3.3.1)
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)
起動時間はマシンごとに異なりますが、JVM で実行されている Spring Boot アプリケーションよりもはるかに高速です。

Web ブラウザーを localhost:8080 で開くと、次の出力が表示されるはずです。

Hello World!

アプリケーションを正常に終了するには、ctrl-c を押します。