静的またはほぼ静的にリンクされたネイティブ実行可能ファイルのビルド
GraalVMネイティブ・イメージでは、デフォルトで動的にリンクされたバイナリがビルドされます。ビルド時に、アプリケーション・クラスおよびインタフェースがロードされ、動的リンクの処理中にフックされます。
ただし、必要に応じて、静的またはほぼ静的にリンクされたネイティブ実行可能ファイルを作成できます。
静的なネイティブ実行可能ファイルとは、静的にリンクされたバイナリのことであり、追加のライブラリ依存性なしに使用できます。静的なネイティブ実行可能ファイは、スリムすなわちdistrolessのコンテナ(スクラッチ・コンテナ)に簡単に配布およびデプロイできます。静的なネイティブ実行可能ファイルを作成するには、静的にmusl-libc (軽量、高速かつ単純なlibc実装)をリンクします。
ほぼ静的なネイティブ実行可能ファイルとは、標準のCライブラリlibcを除くすべて(zlib、JDK共有ライブラリ)をリンクするバイナリのことです。これは、すべてを静的にリンクするための代替オプションです。また、ユーザーのコードによっては、libstdc+およびlibgccをリンクできます。このアプローチは、distrolessコンテナ・イメージへのデプロイメントに最適です。
ノート: 現在は、
libcにリンクされている場合のみ機能します。
このガイドでは、完全に動的、完全に静的、ほぼ静的(libcを除く)などのネイティブ・イメージ・リンク・オプションを利用して、デプロイメント・シナリオに最適な実行可能ファイルを生成する方法を示します。
目次
前提条件および準備
次の前提条件を満たす必要があります:
- Linux AMD64オペレーティング・システム
- Java 17以上のGraalVMディストリビューション
- 64ビットの
muslツールチェーン、makeおよびconfigure - 最新の
zlibライブラリ
-
GraalVM JDKがインストール済であることを確認します。最も簡単に始めるには、SDKMAN!を使用します。その他のインストール・オプションについては、「ダウンロード」セクションを参照してください。
-
次に、
muslツールチェーンをインストールし、zlibをコンパイルしてツールチェーンにインストールする必要があります。musl.ccからmuslツールチェーンをダウンロードします。(こちらをお薦めします)。ツールチェーンを任意のディレクトリに解凍します。このディレクトリは$TOOLCHAIN_DIRとして参照されます。 -
最新の
zlibライブラリ・ソースをzlib.netからダウンロードして解凍します。(このドキュメントでは、zlib-1.2.11を使用します。) CCという名前の新しい環境変数を作成します:CC=$TOOLCHAIN_DIR/bin/gcczlibディレクトリに移動し、次のコマンドを実行してzlibをコンパイルし、ツールチェーンにインストールします:./configure --prefix=$TOOLCHAIN_DIR --static make make install
静的なネイティブ実行可能ファイルのビルド
次のソース・コードがEnvMap.javaファイルに保存されているとします:
import java.util.Map;
public class EnvMap {
public static void main (String[] args) {
var filter = args.length > 0 ? args[0] : "";
Map<String, String> env = System.getenv();
for (String envName : env.keySet()) {
if(envName.contains(filter)) {
System.out.format("%s=%s%n",
envName,
env.get(envName));
}
}
}
}
このアプリケーションは、環境変数を繰り返し処理し、コマンドライン引数として渡される文字のStringを含むものを出力します。
- 最初に、
PATHに$TOOLCHAIN_DIR/binという名前のディレクトリが存在することを確認します。確認するには、次のコマンドを実行します。x86_64-linux-musl-gcc次のような出力が表示されます。
x86_64-linux-musl-gcc: fatal error: no input files compilation terminated. - ファイルをコンパイルします:
javac EnvMap.java - 次のコマンドを実行して、静的なネイティブ実行可能ファイルをビルドします:
native-image --static --libc=musl EnvMapこれにより、静的にリンクされたシステムライブラリを持つネイティブ実行可能ファイルが生成されます。クラスまたはJARファイルの前に他の引数を渡すことができます。
ほぼ静的なネイティブ実行可能ファイルのビルド
GraalVMネイティブ・イメージを使用すると、libc以外のすべてを静的にリンクするほぼ静的なネイティブ実行可能ファイルをビルドできます。libc以外のすべてのライブラリを静的にリンクすることで、アプリケーションがLinux libcベースのディストリビューションで実行するために必要なライブラリがすべて存在することが保証されます。
ほぼ静的なネイティブ実行可能ファイルをビルドするには、このコマンドを使用します:
native-image -H:+StaticExecutableWithDynamicLibC [other arguments] <Class>
前述のEnvMapデモ用のほぼ静的なネイティブ実行可能ファイルをビルドするには、次を実行します:
native-image -H:+StaticExecutableWithDynamicLibC EnvMap
これにより、libc以外のすべての関連ライブラリ(JDK共有ライブラリを含む)に静的にリンクするネイティブ実行可能ファイルが生成されます。これにはzlibが含まれます。また、ユーザーのコードによっては、libstdc+およびlibgccをリンクできます。アプリケーションが依存する動的ライブラリを確認する方法の1つは、ネイティブ実行可能ファイルでlddを実行することです(ldd helloworldなど)。
よくある質問
静的なネイティブ実行可能ファイルまたはほぼ静的なネイティブ実行可能ファイルをデプロイするために推奨されるベースDockerイメージは何ですか。
完全に静的なネイティブ実行可能ファイルでは、ベース・コンテナ・イメージを選択する際の柔軟性が最も高くなります。これは、FROM scratchイメージを含めあらゆるイメージで実行できます。ほぼ静的なネイティブ実行可能ファイルでは、libcが提供されるコンテナ・イメージが必要ですが、それ以外の要件はありません。どちらのケースでも、ベース・コンテナ・イメージの選択は、通常、ネイティブ実行可能ファイルの特定の要件によって異なります。
関連ドキュメント
- Tiny Java Containersのデモでは、シンプルなJavaアプリケーションとシンプルなWebサーバーをコンパイルして、様々な軽量ベース・イメージを使用して非常に小さなDockerコンテナ・イメージを生成する方法を示します。
- Spring Bootアプリケーションのほぼ静的な実行可能ファイルをビルドするためのGraalVMネイティブ・イメージ、Springおよびコンテナ化対話型ラボ。