◀戻る
静的にリンクされた、またはほぼ静的にリンクされたネイティブ実行可能ファイルのビルド
GraalVM Native Imageは、デフォルトでは動的にリンクされたバイナリをビルドします。ビルド時に、まずアプリケーションのクラスとインターフェースを読み込み、動的リンクのプロセスでそれらをフックします。
ただし、必要に応じて、静的にリンクされた、またはほぼ静的にリンクされたネイティブ実行可能ファイルを作成できます。
**静的ネイティブ実行可能ファイル**は、追加のライブラリ依存関係なしで使用できる静的にリンクされたバイナリです。静的ネイティブ実行可能ファイルは、スリムまたはディストロールレスコンテナ(スクラッチコンテナ)に簡単に配布およびデプロイできます。軽量、高速、シンプルなlibc
実装であるmusl-libcに静的にリンクすることで、静的ネイティブ実行可能ファイルを作成できます。
**ほぼ静的なネイティブ実行可能ファイル**は、標準Cライブラリであるlibc
を除き、ネイティブ実行可能ファイルが依存するすべての共有ライブラリ(zlib
、JDK共有静的ライブラリ)をリンクするバイナリです。これは、すべてを静的にリンクする代替オプションです。また、ユーザーのコードによっては、libstdc+
とlibgcc
をリンクする場合があります。このアプローチは、ディストロールレスコンテナイメージへのデプロイに役立ちます。
このガイドでは、完全に動的、完全に静的、ほぼ静的(libc
を除く)などのNative Imageのリンクオプションを活用して、デプロイシナリオに最適な実行可能ファイルを生成する方法を説明します。
前提条件と準備
- Linux x64 オペレーティングシステム
- Java 17 以降の GraalVM ディストリビューション
- 64ビットの
musl
ツールチェーン、make
、およびconfigure
- 最新の
zlib
ライブラリ
GraalVMをインストールする最も簡単な方法は、SDKMAN!を使用することです。その他のインストールオプションについては、ダウンロードセクションをご覧ください。
Native Imageを使用して静的にリンクされたアプリケーションを作成するには、zlib
ライブラリを含むmusl
ツールチェーンが必要です。最適な互換性を得るには、musl-1.2.4以降を使用してください。以下に示すように、ソースからmusl
をビルドすることをお勧めします。
# Specify an installation directory for musl:
export MUSL_HOME=$PWD/musl-toolchain
# Download musl and zlib sources:
curl -O https://musl.libc.org/releases/musl-1.2.4.tar.gz
curl -O https://zlib.net/fossils/zlib-1.2.13.tar.gz
# Build musl from source
tar -xzvf musl-1.2.4.tar.gz
pushd musl-1.2.4
./configure --prefix=$MUSL_HOME --static
# The next operation may require privileged access to system resources, so use sudo
sudo make && make install
popd
# Install a symlink for use by native-image
ln -s $MUSL_HOME/bin/musl-gcc $MUSL_HOME/bin/x86_64-linux-musl-gcc
# Extend the system path and confirm that musl is available by printing its version
export PATH="$MUSL_HOME/bin:$PATH"
x86_64-linux-musl-gcc --version
# Build zlib with musl from source and install into the MUSL_HOME directory
tar -xzvf zlib-1.2.13.tar.gz
pushd zlib-1.2.13
CC=musl-gcc ./configure --prefix=$MUSL_HOME --static
make && make install
popd
要件が設定されたら、デモを作成します。
静的ネイティブ実行可能ファイルのビルド
- 次のソースコードを*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
を含む変数を出力します。 - アプリケーションをコンパイルします
javac EnvMap.java
- 次のコマンドを実行して、静的ネイティブ実行可能ファイルをビルドします
native-image --static --libc=musl EnvMap
これにより、システムライブラリが静的にリンクされたネイティブ実行可能ファイルが生成されます。
./envmap
で実行します。ldd
コマンドを使用して、アプリケーションが完全に静的にリンクされていることを確認できますldd EnvMap
出力は「not a dynamic executable」になります。
ほぼ静的なネイティブ実行可能ファイルのビルド
GraalVM Native Imageを使用すると、libc
を除くすべてを静的にリンクする、ほぼ静的なネイティブ実行可能ファイルをビルドできます。 libc
を除くすべてのライブラリを静的にリンクすることで、アプリケーションはLinux libc
ベースのディストリビューションで実行するために必要なすべてのライブラリを持つことができます。
ほぼ静的なネイティブ実行可能ファイルをビルドするには、次のコマンドを使用します
native-image --static-nolibc [other arguments] <Class>
上記のEnvMap
デモ用にほぼ静的なネイティブ実行可能ファイルをビルドするには、次を実行します
native-image --static-nolibc EnvMap
これにより、libc
を除くすべての関連ライブラリ(JDK共有静的ライブラリを含む)を静的にリンクするネイティブ実行可能ファイルが生成されます。これにはzlib
が含まれます。また、ユーザーのコードによっては、libstdc+
とlibgcc
をリンクする場合があります。アプリケーションが依存する動的ライブラリを確認する1つの方法は、ネイティブ実行可能ファイルでldd
を実行することです(例:ldd envmap
)。
よくある質問
静的またはほぼ静的なネイティブ実行可能ファイルをデプロイするための推奨ベースコンテナイメージは何ですか?
完全に静的なネイティブ実行可能ファイルは、ベースコンテナイメージを選択する際の柔軟性が最も高く、scratch
イメージでも実行できます。 ほぼ静的なネイティブ実行可能ファイルには、libc
、具体的にはglibc
を提供するコンテナイメージが必要ですが、追加の要件はありません。どちらの場合も、ベースコンテナイメージの選択は、一般にネイティブ実行可能ファイルの特定の要件によって異なります。
関連ドキュメント
- Tiny Java Containersデモでは、シンプルなJavaアプリケーションとシンプルなWebサーバーをコンパイルして、さまざまな軽量ベースイメージを使用して非常に小さなDockerコンテナイメージを生成する方法を示しています。
- GraalVM Native Image、Spring、およびコンテナ化インタラクティブラボで、Spring Bootアプリケーションのほぼ静的な実行可能ファイルをビルドします。