タグ別アーカイブ: Graal/GraalVM

Simplifying native-image generation with Maven plugin and embeddable configuration

このエントリは以下のエントリをベースにしています。
The original entry was written by Paul Wögerer (Researcher at Oracle Labs). Working on GraalVM native image generation (Substrate VM).
https://medium.com/graalvm/simplifying-native-image-generation-with-maven-plugin-and-embeddable-configuration-d5b283b92f57

このエントリでは2つの機能をご紹介します。 一つは最近GraalVMに追加された、ネイティブイメージの生成を簡単にするMavenプラグインです。ビルド時にネイティブイメージ生成を含めることができるため、コマンドラインユーティリティを手作業で呼び出す必要はありません。もう一つは、JARファイル内のライブラリの構成を手作業でやらずにすむためのnative-image.propertiesを見ていきます。

Building netty-plot with native-image-maven-plugin

以前のエントリでは、GraalVMネイティブイメージにおけるisolate (分離)と compressed reference (圧縮参照) を利用する方法を紹介しました。

Isolates and Compressed References: More Flexible and Efficient Memory Management via GraalVM
https://medium.com/graalvm/isolates-and-compressed-references-more-flexible-and-efficient-memory-management-for-graalvm-a044cc50b67e

https://logico-jp.io/2019/03/27/isolates-and-compressed-references-more-flexible-and-efficient-memory-management-via-graalvm/

GraalVMのnative-imageツールを使ってネイティブイメージにコンパイルされるuber-jar (fat jar) をMavenを使ってビルドしました。

Ahead-of-time Compilation
https://www.graalvm.org/docs/reference-manual/aot-compilation/

最近のGraalVMリリースでは、ネイティブイメージをMavenでビルドできるようになっています。そのため、uber-jarをビルドした後に別工程でnative-imageツールを実行する必要はありません。

GraalVM Downloads
https://www.graalvm.org/downloads/

このエントリでは、Mavenを使って簡単にネイティブイメージをビルドする方法をご紹介します。GraalVMを JAVA_HOME として使っている場合、以下のようにpom.xmlの pluginsセクションに追加するだけです。

以前のnative-netty-plotの例で言えば、Mavenでネイティブイメージを作成するための追記は上記だけで十分です。 mvn package を実行すればネイティブイメージができあがります。

Isolates for GraalVM Native Images
https://github.com/graalvm/graalvm-demos/tree/master/native-netty-plot

出力結果を見ると、プラグインがどのJARファイルをnative-imageコマンドに渡す必要があるか、実行可能メインクラスが何であるべきか (com.oracle.svm.nettyplot.PlotServer) を導き出したことがわかります。mvn package が完了したら、実行ファイル netty-plotがmavenプロジェクトのtargetディレクトリにあることがわかります。

Maven統合はほとんどのIDEで利用可能なので、MavenプラグインはつまりIDEを離れずにネイティブイメージを生成できる、ということに他なりません。

Plugin customization

<plugin> ノードの<configuration>を使い、イメージ作成のカスタマイズが可能です。現在以下のオプションが利用できます。

<mainClass>

プラグインは、イメージのmainクラスを判断するため、以下の順番でpom.xmlのいくつかの場所をデフォルトで探索します。

  • <maven-shade-plugin> <transformers> <transformer> <mainClass>
  • <maven-assembly-plugin> <archive> <manifest> <mainClass>
  • <maven-jar-plugin> <archive> <manifest> <mainClass>

上記の場所のいずれにおいても適切なmainクラスの定義が見つからない場合、プラグインの<configuration>ノード中に<mainClass>を追加して、カスタムのmainクラスを指定できます。

<imageName>

イメージのファイル名が明示的に設定されていない場合、native-imageツールが選択します(例えば上記のnetty-plotの例の場合、イメージのファイル名はnetty-plotです)。イメージファイル名を指定したい場合は、<imageName>パラメータを使う必要があります。

<buildArgs>

イメージ生成のためにnative-imageコマンドに追加オプションを渡したい場合、<buildArgs>パラメータを利用できます。

Example configuration

mainクラスとしてcom.acme.MeepMeepを使うアサーションを有効にしたイメージをビルドしたい場合、pom.xmlのnative-image-maven-pluginの定義に以下のように追記してください。

Using maven-plugin with GraalVM Enterprise Edition:

JAVA_HOMEとしてGraalVM Enterprise Editionを使う場合、プラグインはエンタープライズ向け機能を有効してイメージを生成します。具体的には、 compressed referencesやその他の最適化が有効になった形で実行ファイルを自動的に生成します。

Oracle Labs GraalVM Download
https://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html

Isolates and Compressed References: More Flexible and Efficient Memory Management via GraalVM
https://medium.com/graalvm/isolates-and-compressed-references-more-flexible-and-efficient-memory-management-for-graalvm-a044cc50b67e

Using maven-plugin without GraalVM:

このプラグインを使うと、GraalVMを手元のシステムにインストールしなくてもイメージを作成できます。唯一の要求事項は、マシン上のJDKがJVMCI対応していることです。現時点では、イメージ生成はJava 8のみサポートしている(Java 11でもサポートするよう鋭意作業中です)ため、JVMCI対応のOpenJDK 8をダウンロードする必要があります。

jvmci-0.56
https://github.com/graalvm/openjdk8-jvmci-builder/releases

JVMCI対応のJDKをダウンロードし、JAVA_HOMEに設定したら、Mavenプロジェクトで上記のnative-image-maven-pluginのスニペットを利用でき、イメージ作成が機能します。動作する理由は、プラグインにより、Mavenがイメージ生成に必要なすべてのコンポーネントを直接Maven Centralからダウンロードするからです。この方式では、ほとんどの場合、新しいバージョンへの更新は、単に定義内のタグを変更することです。例えば、1.0-RC15がリリースされた場合には、プラグイン定義を次のように更新するだけで、それ以外の手順は不要です。Mavenが残りをよろしくやってくれます。

⚠ このシナリオで、 --language:--tool:のようなマクロオプションの利用はできませんのでご注意ください。マクロオプションを使う場合、GraalVMそのものをJAVA_HOMEとして設定し、使用する必要があります。また、アップデートされたGraalVMにJVMCI対応JDKが依存する変更が入っている場合、JVMCI対応のJDKもアップデートする必要があります。つまり利用者が対応する必要がありますよ、ということです。

Composable native-image.properties

GraalVMの最近のリリース以降、ネイティブイメージのビルドについて別の重要な改善をしています。JARファイル中のMETA-INF/native-imagenative-image.propertiesファイルを埋め込むことができるようになりました。native-imageツールは、このリソースの場所にあるすべてのファイルを自動的に処理し、それらを使用してnative-imageのコマンドライン引数を作成します。以前のブログエントリのnative-netty-plotの例では、すでにこの機能を利用しています。

Isolates for GraalVM Native Images
https://github.com/graalvm/graalvm-demos/tree/master/native-netty-plot

src/main/resources/META-INF/native-image/com.oracle.substratevm/netty-plotnative-image.propertiesファイルを配置すれば、イメージの構築時に追加の引数は不要です。以下のコマンドを実行するだけで、イメージを作成できます。

native-image -jar target/netty-plot-0.1-jar-with-dependencies.jar

以前は、Nettyを含むイメージを作成する場合、常に以下のような感じで追加コマンドラインオプションが必要でした。

-H:ReflectionConfigurationResources=reflection-config.json 
--delay-class-initialization-to-runtime=io.netty.handler.codec.http.HttpObjectEncoder

動作するようになった理由は、こうした追加フラグをJARファイル自体に埋め込むことができるようになったからです。native-image.propertiesファイルを調べると、netty-plot-0.1-jar-with-dependencies.jarがイメージのクラスパスにあるときに、追加のフラグがnative-imageに渡されることがわかります。

ここでもまた、Nettyを含むイメージを作成するために必要なよく知られたオプションを見つけることができます。上記のファイルでは${.}が使用されていますが、これはnative-image.propertiesファイルの便利な機能で、これを使うと、native-image.propertiesファイルが存在する場所を参照できます。この方法で、native-image.propertiesファイルの場所を基準にしてリソースの場所を簡単に指定できます。上記の場合、${.}META-INF/native-image/com.oracle.substratevm/netty-plotに展開します。

Making Java libraries native-image compatible by default

正しく適用すれば、Javaライブラリの作者は上述のメカニズムを使ってライブラリにnative-image互換性を持たせることができます。Nettyの例では、com.oracle.svm.nettyplot.NettySubstitutionsからの置換に加え、以下を含むアーティファクトio.netty:netty-allがあれば、

META-INF/native-image/io.netty/netty-all/reflection-config.json META-INF/native-image/io.netty/netty-all/native-image.properties

Nettyはそのままnative-imageとともに利用できます。netty-plotの例のもう一つのnative-image.propertiesには、netty-plot自体が必要とするオプションのみが含まれています。

これに加え、pom.xmlから依存関係com.oracle.substratevm:svmを取り除くことができるようになるでしょう。これはNettySubstitutionsが依存しているために現時点のみ必要としているからです。

💡 About provided

上記で使用したprovidedが重要なのは、イメージビルダー自体がcom.oracle.substratevm:svmを提供するイメージ構築中にのみ置換を必要とするためです。このスコープ定義を省略すると、Mavenは、uber-jarを作成するときにcom.oracle.substratevm:svmcom.oracle.substratevm:svmのすべての推移的な依存関係をjarファイルに入れてしまいます。それは絶対に避けたいのです!

com.oracle.substratevm:svm:
https://search.maven.org/artifact/com.oracle.substratevm/svm/1.0.0-rc14/jar

io.netty:netty-allに native-images で利用する上で必要なすべての具体的な依存関係が含まれている場合、netty-plotへの上記の依存関係は以下のように簡単にできるでしょう。その理由は、netty-plot自体は公式のAPI (org.graalvm.nativeimage API) にのみ依存しているためです。

org.graalvm.nativeimage
https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/package-summary.html

Conclusion

このエントリはGraalVMネイティブイメージMavenプラグインを使って皆様のプロジェクトから簡単にネイティブイメージを作成できることをご紹介しました。また、JARファイルのMETA-INF/native-imageディレクトリに必要なネイティブイメージの細々とした設定をライブラリが埋め込む方法も調べました。

これらの2個の機能により、エコシステムがGraalVMのネイティブイメージやAhead of Time Compilation(事前コンパイル、AOTコンパイル)を活用できるようになります。GraalVMをダウンロードして試してみてください。

GraalVM Downloads
https://www.graalvm.org/downloads

見逃している良い機能を見たいとか、あるいは他に何かフィードバックすることがありましたら、ご連絡ください。GraalVMのGitHubリポジトリにIssueを残すとか、その他の方法でご連絡ください。

GraalVM GitHub Repository
https://github.com/oracle/graal

GraalVM Community
http://www.graalvm.org/community/

Next-generation Kubernetes Native Java Framework implements Eclipse MicroProfile

このエントリは以下のエントリをベースにしています。
The original entry, which was written by John Clingan (Senior Principal Product Manager, Red Hat), is accessible via the following URL.
https://microprofile.io/2019/03/07/next-generation-kubernetes-native-java-framework-implements-eclipse-microprofile/

本日、 Quarkus をオープンソースコミュニティに向けて発表しました。アナウンスの中で以下のように述べています。

“Quarkus is a Kubernetes Native Java framework tailored for GraalVM and HotSpot, crafted from best-of-breed Java libraries and standards.”
(QuarkusはGraalVMとHotSpot用に設計されたKubernetes Native Java Frameworkで、最善のJavaライブラリと標準から作られています。)

Quarkus はコンテナやKubernetes、FaaS (Function as a Service) でのJavaアプリケーションの開発および実行のために素晴らしい体験を提供するようデザインされており、そのため、これらの環境に適した機能を提供しています。

Quarkusを使うとJavaアプリケーションの高速な立ち上がりならびに低メモリフットプリントを実現するため、Kubernetes上やFaaSとしてJavaを実行するためにコンテナの集積度を高めることができるだけでなく、Infinispan、RestEasy、Hibernate、Eclipse Vert.x、Netty、Kubernetes、OpenShift、Jaeger、Prometheus、そしてEclipse MicroProfile 2.1の拡張を含むことにより、エンタープライズ向けの機能も備えています。

Eclipse MicroProfileに関して言えば、Quarkus は以下のEclipse MicroProfile 2.1 APIおよびスタンドアロン仕様をサポートしています。

  • Eclipse MicroProfile Config
  • Eclipse MicroProfile OpenTracing
  • Eclipse MicroProfile Metrics
  • Eclipse MicroProfile Fault Tolerance
  • Eclipse MicroProfile Health
  • Eclipse MicroProfile OpenAPI
  • Eclipse MicroProfile JWT Propagation
  • Eclipse MicroProfile REST Client
  • Eclipse MicroProfile Reactive Streams Operators
  • Eclipse MicroProfile Reactive Messaging (Draft Specification)

Quarkus には開発者にうれしい、以下のような多くの機能が含まれています。

  • 統合された構成:すべての構成は1個のファイルで
  • 構成不要でライブリロード:開発者は自身のアプリを再起動せずにコード作成可能
  • 命令型(Imperative)とリアクティブ型(Reactive)プログラミング」の統合
  • ネイティブバイナリ生成で面倒な作業は不要
  • 80%の一般的な使用法向けにコードを合理化し、残りの20%のための柔軟性を提供

Eclipse MicroProfileコミュニティはこの新しい実装にわくわくしており、Quarkusコミュニティとコラボレーションできることを楽しみにしています。

Quarkusについては以下のURLからどうぞ。

Introducing Quarkus: a next-generation Kubernetes native Java framework
https://developers.redhat.com/blog/2019/03/07/quarkus-next-generation-kubernetes-native-java-framework/

Quarkus — Supersonic Subatomic Java
https://quarkus.io/

quarkus (GitHub)
https://github.com/quarkusio/quarkus

Introducing Quarkus: a next-generation Kubernetes native Java framework

このエントリは以下のエントリをベースにしています。
This entry is based on the one by Jason Greene (Quarkus Co-Founder, Distinguished Engineer and Manager, Red Hat).
https://developers.redhat.com/blog/2019/03/07/quarkus-next-generation-kubernetes-native-java-framework/


オープンソースコミュニティにJavaが現れて20年以上が過ぎましたが、いまなお開発者の間では非常に人気があります。事実、TIOBEインデックスの2位を下回ることは一度もありません。Javaは90年代半ばに生まれ、(仮想化)ホストのCPUとメモリの単独所有を前提とした、非常に動的なモノリシックアプリケーションを実行するため、約20年間にわたって最適化されてきました。しかし、私たちは現在、クラウド、モバイル、IoT、そしてオープンソースによって支配される世界にいます。そこでは、コンテナ、Kubernetes、マイクロサービス、リアクティブ、FaaS、12-factor、そしてクラウドネイティブのアプリケーション開発により、より高いレベルの生産性と効率性をもたらすことができます。業界として、これらの新しいデプロイメント環境とアプリケーションアーキテクチャに対処するためにJavaをどのように利用するのが最もよいかを再考する必要があります。

TIOBE Index for March 2019
https://www.tiobe.com/tiobe-index/
12 factor
https://12factor.net/

そこで、Quarkus Supersonic Subatomic Javaをご紹介したいと思います。

QuarkusとはGraalVMとHotSpot用に設計されたKubernetes Native Java Frameworkで、最善のJavaライブラリと標準から作られています。Quarkusの目標は、JavaをKubernetesおよびサーバーレス環境の主要なプラットフォームにすると同時に、幅広い分散アプリケーションアーキテクチャに最適に対処するための統一された反応的で命令的なプログラミングモデルを開発者に提供することです。

Container First

Quarkusを使うと実行時間を大幅に短縮できます(Red Hatによるテストに基づきます)。具体的には以下の機能を提供します。

./my-native-java-rest-app
Quarkus started in 0.008s
  • Fast Startup(数十ミリ秒)により、コンテナおよびKubernetes上のマイクロサービスの自動スケールアップ・ダウンおよびFaaSの即時実行ができる
  • メモリ使用率が低いため、複数のコンテナを必要とするマイクロサービスアーキテクチャの展開でコンテナ密度を最適化できる
  • アプリケーションとコンテナイメージのフットプリントをさらに小さくできる

Unifies Imperative and Reactive

ほとんどのJava開発者は命令型プログラミングモデルに精通しているので、新しいプラットフォームを採用するときにはその経験を利用したいと考えています。と同時に、開発者はビジネス要件に対処するためにクラウドネイティブ、イベント駆動、非同期、およびリアクティブモデルを急速に採用しており、高度な並行処理でレスポンシブなアプリケーションを構築しています。Quarkusは、2つのモデルを同じプラットフォームにシームレスに統合して、組織内で強力に活用できるように設計されています。

Developer Joy

開発者の喜びのために最適化されたまとまりのあるプラットフォームを提供します。

$ mvn package -Pnative
  # or
$gradle quarkus-native
  • すべての設定は単一のプロパティファイルにまとめて管理します
  • 構成不要で、瞬く間にライブでリロードします
  • 80%の一般的な使用法向けにコードを合理化し、残りの20%のための柔軟性をもたらします
  • ネイティブ実行可能ファイルの生成で面倒なことをする必要はありません

Best of Breed Libraries and Standards

Quarkusは、お好みかつ標準的なバックボーンで使う最適なライブラリを活用する、まとまりのある、使いやすい、フルスタックのフレームワークです。ここでバックボーンとはEclipse MicroProfile、JPA/Hibernate、JAX-RS/Hibernete、Eclipse Vert.x、Nettyなどのことです。

Quarkusには、サードパーティのフレームワークの作者が自身のフレームワークを拡張するために活用できる拡張フレームワークも含まれています。Quarkus拡張フレームワークは、サードパーティ製フレームワークをQuarkus上で実行し、GraalVMネイティブバイナリにコンパイルするための複雑さを軽減します。

Summary

上記のことを念頭において設計されているため、Quarkusはサーバーレス、マイクロサービス、コンテナ、Kubernetes、FaaS、およびクラウドというこの新しい世界におけるJava実行のための効果的なソリューションたり得るでしょう。クラウドネイティブのJavaアプリケーションに対するそのcontainer-firstアプローチは、マイクロサービス開発のための命令型および理アクティブ・プログラミングパラダイムを統合し、Javaを使った開発に革命をもたらすことを約束する拡張可能な標準ベースのエンタープライズJavaライブラリおよびフレームワークのセットを提供します。

Quarkusオープンソースコミュニティへのご参加をお待ちしております。Quarkusの改良、サードパーティ製の拡張機能の開発、Quarkusを使用したアプリケーションの開発を継続して支援したいと思ってらっしゃる場合、またはご興味がある場合は、以下のURLからどうぞ。


ということで、Getting Start Guideに従ってちょっとさわってみました。このQuick Startで必要なものは、GraalVM、Mavenです。IDEも必要と書いてありますが、なくてもOKです。GraalVMを使う時点で、Java 8を前提にしていますが、今後Java 11以後の機能が使えるように機能追加されていくことでしょう。

QUARKUS — CREATING YOUR FIRST APPLICATION
https://quarkus.io/guides/getting-started-guide

Mavenでプロジェクトを生成してプロジェクト内を見ると、GreetingResource.javaという、見慣れたJAX-RSのコードが見つかりますが、以下の注記にある通り、Applicationクラスを作成するコードがありません。

With Quarkus there is no need to create an Application class. It’s supported but not required. In addition, only one instance of the resource is created and not one per request. You can configure this using the different *Scoped annotations (ApplicationScoped, RequestScoped, etc).

その他特に詰まるところはないと思います。「必要なコードだけ書けばよい」というのはありがたいことです。

Native Imageを作るチュートリアルもありますが、native-imageコマンドでごにょごにょする部分もMavenにお任せです。

QUARKUS — BUILDING A NATIVE IMAGE
https://quarkus.io/guides/building-native-image-guide.html

macOSの環境では、チュートリアルのアプリケーションのexecutable jarファイルは36KB程度ですが、Nativeイメージのサイズは19MB超…。

Dockerfileはプロジェクト生成時に自動作成されており、Native ImageをDockerイメージにパッケージングすることもできます。

普通にDockerイメージを作成すると125MBになってしまうのですが、もっとサイズを小さくするためのdistrolessバージョンなるものがあるようです。

Distroless base image
https://github.com/quarkusio/quarkus/tree/master/docker/distroless

Dockerfileを書き換えて、 docker build した際のイメージは、37.2MBになりました。環境に依存しますが、当方の環境では起動時間は下図のような感じです。