web-dev-qa-db-ja.com

Java 11アプリケーション(軽量ドッカーイメージとして)

質問に触発 なぜJava 11ベースDockerイメージがこんなに大きいのですか?(openjdk:11-jre-slim) このトピックはJava worldまだ解決されていません。

07 Dec 2018に関しては、一般的な問題/落とし穴があります(上記のチケットで説明):

これらの問題の結果として、slimOracle Java 11ベースイメージは非常に重く、不安定であると見なされます。 https:// hub。 docker.com/_/openjdk/

質問は次のとおりです。

最適化されたまたは推奨される構築方法と配信方法Java Dockerイメージとしての11のアプリケーション

38
radistao

2019年7月からのUPDhttps://stackoverflow.com/a/57145029/907576

これまで、単純なスプリングブートアプリケーション(RESTエンドポイントが1つのみ)の例として、次のソリューションを見つけることができました(アプリケーションjarがDockerビルドの前にbuild/libs/spring-boot-demo.jarにあると考えてください)。

  1. Jediパス使用したい場合安定したスリムなLinuxバージョンでの公式のOracle OpenJDKディストリビューション(今のところDebian 9 "Stretch" ):

    • debian:stretch-slim(最新の安定版)ベースイメージを使用
    • Dockerマルチステージビルド を使用します

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

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

        • コンパイル済みの最小Javaディストリビューションをステージ1から新しいイメージにコピーします
        • javaにアクセスするためのパスを構成する
        • アプリケーションjarをイメージにコピーします

    したがって、最終的なDockerfileはこのように見えます

    JDK VERSIONURLおよびHASHの値を実現する):

    # 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の例(Java.base,Java.sql,Java.naming,Java.desktop,Java.management,Java.security.jgss,Java.instrument)には5つのJavaモジュールが含まれています。アプリケーションを「手動」で実行し、ClassNotFoundExceptionを修正しました。 PropertyEditorSupportにのみ使用されるように思われるJava.desktopのようないくつかの冗長な依存関係を削除するのと同じように、Javaモジュールがいつ含まれるか、Spring Boot開発者の推奨事項/ガイドをさらに待つ
    • いくつかのモジュールを見逃すことを恐れている場合-それらは非常に軽量であり、それらすべてを合わせて約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ディストリビューションを使用した簡単な方法

    Oracleの反対 AzulのZulu JDK 11Alpineポート をサポートし、それぞれのベース 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" ]

結果のイメージは、ストリッピングされたAlpine分布で予想されるように、73 MBです。

52
radistao

2019年7月現在

:最初の段階のイメージは、fatのようになります:debian/ubuntuを使用できます/ whateverおよびinclude git/gradle/whatever-これは最終的な結果の画像サイズには影響しません。これは最後の(2番目の)ステージに完全に基づいています)

Alpineコミュニティリポジトリ の使用

FROM Alpine:latest as packager

RUN apk --no-cache add openjdk11-jdk openjdk11-jmods

ENV Java_MINIMAL="/opt/Java-minimal"

# build minimal JRE
RUN /usr/lib/jvm/Java-11-openjdk/bin/jlink \
    --verbose \
    --add-modules \
        Java.base,Java.sql,Java.naming,Java.desktop,Java.management,Java.security.jgss,Java.instrument \
    --compress 2 --strip-debug --no-header-files --no-man-pages \
    --release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE" \
    --output "$Java_MINIMAL"

FROM Alpine:latest

ENV Java_HOME=/opt/Java-minimal
ENV PATH="$PATH:$Java_HOME/bin"

COPY --from=packager "$Java_HOME" "$Java_HOME"
COPY build/libs/application.jar app.jar

ENTRYPOINT ["Java","-jar","/app.jar"]

AdoptOpenJDK の使用

FROM adoptopenjdk/openjdk11:x86_64-Alpine-jdk-11.0.4_11 as packager

ENV Java_MINIMAL="/opt/Java-minimal"

# build minimal JRE
RUN jlink \
    --verbose \
    --add-modules \
        Java.base,Java.sql,Java.naming,Java.desktop,Java.management,Java.security.jgss,Java.instrument \
    --compress 2 --strip-debug --no-header-files --no-man-pages \
    --output "$Java_MINIMAL"

FROM Alpine:latest

# magic to make Java binaries work in Alpine
# https://github.com/AdoptOpenJDK/openjdk-docker/blob/master/11/jdk/Alpine/Dockerfile.hotspot.releases.slim#L24-L54
RUN apk add --no-cache --virtual .build-deps curl binutils \
    && GLIBC_VER="2.29-r0" \
    && Alpine_GLIBC_REPO="https://github.com/sgerrand/Alpine-pkg-glibc/releases/download" \
    && GCC_LIBS_URL="https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-9.1.0-2-x86_64.pkg.tar.xz" \
    && GCC_LIBS_SHA256="91dba90f3c20d32fcf7f1dbe91523653018aa0b8d2230b00f822f6722804cf08" \
    && ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-3-x86_64.pkg.tar.xz" \
    && ZLIB_SHA256=17aede0b9f8baa789c5aa3f358fbf8c68a5f1228c5e6cba1a5dd34102ef4d4e5 \
    && curl -LfsS https://Alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
    && SGERRAND_RSA_SHA256="823b54589c93b02497f1ba4dc622eaef9c813e6b0f0ebbb2f771e32adf9f4ef2" \
    && echo "${SGERRAND_RSA_SHA256} */etc/apk/keys/sgerrand.rsa.pub" | sha256sum -c - \
    && curl -LfsS ${Alpine_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/glibc-${GLIBC_VER}.apk \
    && apk add /tmp/glibc-${GLIBC_VER}.apk \
    && curl -LfsS ${Alpine_GLIBC_REPO}/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk > /tmp/glibc-bin-${GLIBC_VER}.apk \
    && apk add /tmp/glibc-bin-${GLIBC_VER}.apk \
    && curl -Ls ${Alpine_GLIBC_REPO}/${GLIBC_VER}/glibc-i18n-${GLIBC_VER}.apk > /tmp/glibc-i18n-${GLIBC_VER}.apk \
    && apk add /tmp/glibc-i18n-${GLIBC_VER}.apk \
    && /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true \
    && echo "export LANG=$LANG" > /etc/profile.d/locale.sh \
    && curl -LfsS ${GCC_LIBS_URL} -o /tmp/gcc-libs.tar.xz \
    && echo "${GCC_LIBS_SHA256} */tmp/gcc-libs.tar.xz" | sha256sum -c - \
    && mkdir /tmp/gcc \
    && tar -xf /tmp/gcc-libs.tar.xz -C /tmp/gcc \
    && mv /tmp/gcc/usr/lib/libgcc* /tmp/gcc/usr/lib/libstdc++* /usr/glibc-compat/lib \
    && strip /usr/glibc-compat/lib/libgcc_s.so.* /usr/glibc-compat/lib/libstdc++.so* \
    && curl -LfsS ${ZLIB_URL} -o /tmp/libz.tar.xz \
    && echo "${ZLIB_SHA256} */tmp/libz.tar.xz" | sha256sum -c - \
    && mkdir /tmp/libz \
    && tar -xf /tmp/libz.tar.xz -C /tmp/libz \
    && mv /tmp/libz/usr/lib/libz.so* /usr/glibc-compat/lib \
    && apk del --purge .build-deps glibc-i18n \
    && rm -rf /tmp/*.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*

ENV Java_HOME=/opt/Java-minimal
ENV PATH="$PATH:$Java_HOME/bin"

COPY --from=packager "$Java_HOME" "$Java_HOME"
COPY build/libs/application.jar app.jar

ENTRYPOINT ["Java","-jar","/app.jar"]

https://blog.gilliard.lol/2018/11/05/Alpine-jdk11-images.html も読んでください

3
radistao

radistao(クールなもの!)による回答に基づいて、 Amazon Corretto JDK11ベースのイメージ を作成しました。 DockerHub でも利用可能です。

最小maslick/minimalka:jdk11Correttoイメージは〜108MB(55MB Dockerhubで圧縮)。

単純なSpringboot jarを追加すると、結果のイメージは〜125MB(Dockerhubで71MB圧縮)になります。

FROM maslick/minimalka:jdk11
WORKDIR /app
EXPOSE 8080
COPY my-cool-app.jar ./app.jar
CMD Java $Java_OPTIONS -jar app.jar
docker build -t my-cool-app:latest .
docker run docker run -d my-cool-app
1
maslick