<前回までの作業>
さて、Springbootを使い、Webアプリケーションサーバを構築する事はできました。
「占いウェブアプリ」の構築手順はこちらです。
https://qiita.com/naiveprince0507/items/24a80b89c5e39ad9f6c7
<今回のタスク>
今回は、WebアプリケーションをNative Image化します。
<作業概略と基本資料>
これが本当に上手く行かずに、苦労しまくったので、何が問題なのか? を記載します。
・本件全般に関する技術概要はこちら。
Springbootフレームワークと、そのアプリのNative Image化手法
https://future-architect.github.io/articles/20210909a/
・ 作業の基本手順はこちら。
https://spring.pleiades.io/spring-boot/docs/current/reference/html/native-image.html
<ちょっと説明>
因みに、ネイティブイメージ化に関しては、上記サイトに詳述されております。
GraalVM ネイティブイメージの導入
GraalVM ネイティブイメージは、Java アプリケーションをデプロイして実行する新しい方法を提供します。Java 仮想マシンと比較して、ネイティブイメージはより少ないメモリフットプリントで実行でき、はるかに高速な起動時間で実行できます。
これらは、コンテナー イメージを使用してデプロイされるアプリケーションに適しており、"Function as a service" (FaaS) プラットフォームと組み合わせると特に興味深いものになります。
JVM 用に作成された従来のアプリケーションとは異なり、GraalVM ネイティブイメージアプリケーションでは、実行可能ファイルを作成するために事前処理が必要です。この事前処理には、メインエントリポイントからアプリケーションコードを静的に分析することが含まれます。
GraalVM ネイティブイメージは、プラットフォーム固有の完全な実行可能ファイルです。ネイティブイメージを実行するために Java 仮想マシンを提供する必要はありません。
ビルド時に Spring が事前処理を実行し、GraalVM が使用できる追加のアセットを生成することが可能になります。
■ 問題点の整理
問題点1. Springbootプラグインの問題
SpringbootアプリをNative Image化する際に2つの方法があるのだが、実は、ここに罠がある。
Spring Boot ネイティブイメージアプリケーションを構築するには、主に次の 2 つのメソッドがあります。
a) Cloud Native Buildpacks の Spring Boot サポートを使用して、ネイティブ実行可能ファイルを含む軽量コンテナーを生成します。
b) GraalVM ネイティブビルドツールを使用してネイティブ実行可能ファイルを生成します。
2つの方法の内、コンテナ化まで自動実行で作成してしまうのがa)の方法で、SpringbootアプリをJDKまで含めてネイティブイメージ化する(コンテナ化はしない)のが、b)の方法です。
当然、a)の方法の方が、ラクそうで良いのですが(NativeアプリをOS上で動かす事はあまり想定されず、最終的にはコンテナ上で動作させる事が大部分と思うので)、このCloud Native Buildpacksは、Spring Initilizarのプラグインから、なぜか消えております。(2023年9月6日現在)。
尚、複数のネット情報からすると少し前には、Cloud Native Buildpacksのプラグインはあった筈なので、「なぜないんだ?」と探すのに、凄い時間が掛かった。
と言うわけで、現時点では、b)の方法しかありません。
尚、a)の方法では、ローカルPCにGraalVMがインストールされてなくても、Native Image化できます。(Dockerの機能でNative Image化を行う為。)
しかし、b)の方法では、ローカルPC上にGraalVMがインストールされている必要があります。
GraalVMがインストールされている事をターミナル上確認します。
kanashimi_usr@kanashimi_usr-mac ~ % java -version
java version "17.0.6" 2023-01-17 LTS
Java(TM) SE Runtime Environment GraalVM CE 22.3.1 (build 17.0.6+9-LTS-jvmci-22.3-b11)
Java HotSpot(TM) 64-Bit Server VM GraalVM CE 22.3.1 (build 17.0.6+9-LTS-jvmci-22.3-b11, mixed mode, sharing)
kanashimi_usr@kanashimi_usr-mac ~ %
無い場合は、ここから、無料でDLできます。(オープンソースです。)
https://www.graalvm.org/downloads/
問題点 2. IntelliJの問題
IDE(IntelliJ上での"GraalVM Native Support"のプラグインを入れるだけでOk。
これはとても簡単。
"GraalVM Native Support"プラグインをインストールしているので、"nativeCompile"コマンドの操作もIDE上に出てくる。よって、ここをRunすれば、Native Imageがビルドできる筈なのだが、IDE上で実行するとなぜかエラーが起きる。
ビルド時に非常に多くのエラーが出て、Debuggingを一つずつ進めたのだが、これが本当に上手く行かない。
これで4日を潰した。そして、今も解決できていない。
ただ、非常に不思議なことに、IDE上ではなく、ターミナルを開いて、該当フォルダにて、"gradle nativeCompile"のコマンドを走らせると、ビルドできる。(これは、おそらくIntelliJの問題と思う。)
よって、Terminal上で、同コマンドを走らせます。
kanashimi_usr@kanashimi_usr-mac test0906 % gradle nativeCompile
ターミナル上で走らせたら、動いた!
問題点 3. Webアプリ自体の問題。(私の技術力の問題)
冒頭で紹介した、「占いウェブアプリ」をNative Image化しようとするのですが、これは上手く、Native Image化できない。
Native Image化に当たっては、アプリによって、微妙なチューニングが必要になることが多々あるので、今回も死ぬ程、「占いウェブアプリ」自体を書き直したりしたが、さまざまなパッチを当てたが、どうしてもNative Image化できなかった。(これは、私自身の技術力の問題。)
■ 回避策
やりたい事は、Webアプリの開発ではなく、SpringbootアプリのNative Image化であるから、話を単純化して実行することにする。上記3つの問題点を回避する為に、結局、下記の設定ですることにした。
・ GraalVM Native Build Toolsを使う。(Buildpackは使わない。無いから使えない。)
・ IDE(IntelliJ)の機能を使って、Nativeビルドしない。ターミナル上でビルドする。
・ 冒頭の「占いウェブアプリ」をNativeビルド化するのはとりあえず諦めて、超単純な、HelloWorld!をSpringbootで作り直して、それをビルドする。
■ 構築作業
と言うわけで実際の構築は下記。
1)まず、SpringIntializeで下記の様に設定。
Gradleを選び、PackagingはJar。
Dependencyは、SpringWebとGraalVM Native Supportのみ。
https://start.spring.io/
2)HelloController.javaというクラスを作成し、下記の様に書く。
コードはこれ。
package com.example.test0906;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
3)IDE上ではなく、ターミナルを開いて、下記のコマンドを打ち込み、ビルドする。
kanashimi_usr@kanashimi_usr-mac test0906 % gradle nativeCompile
Buildが成功すると、build/native/nativeCompileのフォルダの下にNativeファイルが作成される。
4) ターミナル上で、Runしてみる。
こんな感じ。
kanashimi_usr@kanashimi_usr-mac test0906 % build/native/nativeCompile/test0906
無事に表示されました!
kanashimi_usr@kanashimi_usr-mac ~ % curl -l localhost:8080
Greetings from Spring Boot!%
苦節1週間の苦行でした!