戻る

静的にリンクされた、またはほぼ静的にリンクされたネイティブ実行可能ファイルのビルド

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

要件が設定されたら、デモを作成します。

静的ネイティブ実行可能ファイルのビルド

  1. 次のソースコードを*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を含む変数を出力します。

  2. アプリケーションをコンパイルします
     javac EnvMap.java
    
  3. 次のコマンドを実行して、静的ネイティブ実行可能ファイルをビルドします
     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アプリケーションのほぼ静的な実行可能ファイルをビルドします。

お問い合わせ