LoginSignup
0
0

【Mac M1環境】SpringbootアプリをNative Image化(IDEはIntelliJ)するのに、死ぬ程、苦労した話。

Last updated at Posted at 2023-09-06

<前回までの作業>
さて、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。
これはとても簡単。
image.png

"GraalVM Native Support"プラグインをインストールしているので、"nativeCompile"コマンドの操作もIDE上に出てくる。よって、ここをRunすれば、Native Imageがビルドできる筈なのだが、IDE上で実行するとなぜかエラーが起きる。
名称未設定3.png
ビルド時に非常に多くのエラーが出て、Debuggingを一つずつ進めたのだが、これが本当に上手く行かない。
これで4日を潰した。そして、今も解決できていない。
ただ、非常に不思議なことに、IDE上ではなく、ターミナルを開いて、該当フォルダにて、"gradle nativeCompile"のコマンドを走らせると、ビルドできる。(これは、おそらくIntelliJの問題と思う。)
よって、Terminal上で、同コマンドを走らせます。

kanashimi_usr@kanashimi_usr-mac test0906 % gradle nativeCompile

名称未設定4.png

ターミナル上で走らせたら、動いた!

問題点 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/
image.png

2)HelloController.javaというクラスを作成し、下記の様に書く。
image.png

コードはこれ。

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ファイルが作成される。
名称未設定5.jpg

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週間の苦行でした!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0