1. ホーム
  2. java

[解決済み] Java 11 アプリケーションを軽量な docker イメージで提供

2023-07-31 17:08:07

質問

質問から発想する なぜJava 11のベースDockerイメージはこんなに大きいのですか?(openjdk:11-jre-slim) Java界隈のこのトピックはまだ決着がついていないことがわかりました。

については 07 Dec 2018 については、共通の問題/落とし穴があります (上記のチケットで説明されています)。

これらの問題の結果 スリム Oracle Java 11 の基本イメージはかなり重く、不安定であると考えられています。 https://hub.docker.com/_/openjdk/

ということで、質問です。

は何ですか? 最適化された または 推奨 Java 11 アプリケーションを docker イメージとして構築し配信する方法 ?

どのように解決するのですか?

2019年7月よりUPD : https://stackoverflow.com/a/57145029/907576

単純な Spring Boot アプリケーション (REST エンドポイントが 1 つだけ) を例にとると、今のところ次のような解決策があります (アプリケーションの jar が build/libs/spring-boot-demo.jar にあると仮定します。

  1. ジェダイ・パス を使いたい場合は 公式の Oracle OpenJDK ディストリビューションを安定版スリム Linux で使用する場合 ( Debian 9 "Stretch" 今のところ)。

    • 使用 debian:stretch-slim (最新の安定版)ベースイメージ
    • 使用 Dockerの多段ビルド

      1. 最初のDockerビルドステージ。

        • ダウンロードとインストール Oracle OpenJDK アーカイブを最初のDockerビルドステージにインストールします。
        • を使用して、プロジェクト用の最小限のJavaディストリビューション(別名JRE)をコンパイルします。 jlink ツール
      2. 2つ目のDockerビルドステージ。

        • ステージ1から新しいイメージにコンパイルされた最小限のJavaディストリビューションをコピーします。
        • Javaにアクセスするためのパスを設定します。
        • アプリケーションのjarをイメージにコピーする

    では、最終的に Dockerfile は次のようになります。

    ( JDKを実現する VERSION , URLHASH ):

    # First stage: JDK 11 with modules required for Spring Boot
    FROM debian:stretch-slim as packager
    
    # source JDK distribution names
    # update from https://jdk.java.net/java-se-ri/11
    ENV JDK_VERSION="11.0.1"
    ENV JDK_URL="https://download.java.net/java/GA/jdk11/13/GPL/openjdk-${JDK_VERSION}_linux-x64_bin.tar.gz"
    ENV JDK_HASH="7a6bb980b9c91c478421f865087ad2d69086a0583aeeb9e69204785e8e97dcfd"
    ENV JDK_HASH_FILE="${JDK_ARJ_FILE}.sha2"
    ENV JDK_ARJ_FILE="openjdk-${JDK_VERSION}.tar.gz"
    # target JDK installation names
    ENV OPT="/opt"
    ENV JKD_DIR_NAME="jdk-${JDK_VERSION}"
    ENV JAVA_HOME="${OPT}/${JKD_DIR_NAME}"
    ENV JAVA_MINIMAL="${OPT}/java-minimal"
    
    # downlodad JDK to the local file
    ADD "$JDK_URL" "$JDK_ARJ_FILE"
    
    # verify downloaded file hashsum
    RUN { \
            echo "Verify downloaded JDK file $JDK_ARJ_FILE:" && \
            echo "$JDK_HASH $JDK_ARJ_FILE" > "$JDK_HASH_FILE" && \
            sha256sum -c "$JDK_HASH_FILE" ; \
        }
    
    # extract JDK and add to PATH
    RUN { \
            echo "Unpack downloaded JDK to ${JAVA_HOME}/:" && \
            mkdir -p "$OPT" && \
            tar xf "$JDK_ARJ_FILE" -C "$OPT" ; \
        }
    ENV PATH="$PATH:$JAVA_HOME/bin"
    
    RUN { \
            java --version ; \
            echo "jlink version:" && \
            jlink --version ; \
        }
    
    # build modules distribution
    RUN jlink \
        --verbose \
        --add-modules \
            java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
            # java.naming - javax/naming/NamingException
            # java.desktop - java/beans/PropertyEditorSupport
            # java.management - javax/management/MBeanServer
            # java.security.jgss - org/ietf/jgss/GSSException
            # java.instrument - java/lang/instrument/IllegalClassFormatException
        --compress 2 \
        --strip-debug \
        --no-header-files \
        --no-man-pages \
        --output "$JAVA_MINIMAL"
    
    # Second stage, add only our minimal "JRE" distr and our app
    FROM debian:stretch-slim
    
    ENV JAVA_HOME=/opt/java-minimal
    ENV PATH="$PATH:$JAVA_HOME/bin"
    
    COPY --from=packager "$JAVA_HOME" "$JAVA_HOME"
    COPY "build/libs/spring-boot-demo.jar" "/app.jar"
    
    EXPOSE 8080
    CMD [ "-jar", "/app.jar" ]
    ENTRYPOINT [ "java" ]
    
    

    注意 :

    • 最小限の JRE の例には、5 つの Java モジュールが含まれています ( java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument ). 私はそれらを手動で発見し、アプリケーションを実行し、修正しました。 ClassNotFoundException . どのJavaモジュールをいつインクルードするか、また、以下のような冗長な依存関係を削除するのと同様に、Spring Boot開発者の推奨/ガイドを待っている。 java.desktop のみに使用されているようです。 PropertyEditorSupport
    • これらのモジュールは非常に軽量で、すべて合わせると約 2 MB のサイズアップになります。の完全なリストを取得します。 java.*jdk.* 11 のモジュールです。

      java --list-modules | grep -E "^java\.[^@]*" | cut -d @ -f 1

      java --list-modules | grep -E "^jdk\.[^@]*" | cut -d @ -f 1

    私の場合、結果の画像サイズは 123 MB で、最小限の7つのSpring Bootモジュールと 125 MB で、すべての java.* モジュール

    このビルドワークフローのオプションの改善として :

    • ダウンロードしたJDKを展開したイメージをプリビルドし、第一段階のベースイメージとして使用する。
    • 毎回インクルードするモジュールがわかっている場合、最小限の JRE とインクルードモジュールをコンパイルしたベースイメージをプリビルドします。
  2. 簡単な方法 ベンダーの Open JDK ディストリビューション :

    オラクルとは逆 AzulのZulu JDK 11 サポート アルパイン・ポート をサポートし、それぞれのベースとなる Dockerイメージ .

このように、Zulu JVM/JDKを尊重すれば、Dockerのビルドはよりシンプルになります。

FROM azul/zulu-openjdk-alpine:11 as packager

RUN { \
        java --version ; \
        echo "jlink version:" && \
        jlink --version ; \
    }

ENV JAVA_MINIMAL=/opt/jre

# build modules distribution
RUN jlink \
    --verbose \
    --add-modules \
        java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
        # java.naming - javax/naming/NamingException
        # java.desktop - java/beans/PropertyEditorSupport
        # java.management - javax/management/MBeanServer
        # java.security.jgss - org/ietf/jgss/GSSException
        # java.instrument - java/lang/instrument/IllegalClassFormatException
    --compress 2 \
    --strip-debug \
    --no-header-files \
    --no-man-pages \
    --output "$JAVA_MINIMAL"

# Second stage, add only our minimal "JRE" distr and our app
FROM alpine

ENV JAVA_MINIMAL=/opt/jre
ENV PATH="$PATH:$JAVA_MINIMAL/bin"

COPY --from=packager "$JAVA_MINIMAL" "$JAVA_MINIMAL"
COPY "build/libs/spring-boot-demo.jar" "/app.jar"

EXPOSE 8080
CMD [ "-jar", "/app.jar" ]
ENTRYPOINT [ "java" ]

出来上がった画像は 73 MB で、さすがにアルパインディストリビューションを剥がしただけのことはあります。