静的またはほぼ静的にリンクされたネイティブ実行可能ファイルのビルド
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/gcc
zlib
ディレクトリに移動し、次のコマンドを実行して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およびコンテナ化対話型ラボ。