Inspiré par la question Pourquoi l'image Docker de base Java 11 est-elle si grande? (Openjdk: 11-jre-slim) J'ai découvert que ce sujet était traité dans Java monde n'est toujours pas réglé.
En ce qui concerne 07 Dec 2018
, il existe des problèmes/pièges courants (décrits dans le ticket ci-dessus):
JRE n'est pas distribué en tant que "package" séparé. Les modules de JDK doivent être utilisés à la place
Oracle OpenJDK 11 ne prend pas en charge Linux Alpine , donc des images légères ne peuvent pas être facilement créées
les images Oracle openjdk-11 actuellement disponibles permettent de créer un module libjvm.so
non déshabillé, qui contient des centaines de mégaoctets et doit être supprimé séparément:
En raison de ces problèmes, même slim Oracle Java 11 images de base sont assez lourds et considérés comme instables: https: // hub. docker.com/_/openjdk/
La question est donc:
quelles sont les manières optimisées ou de construire et de livrer Java 11 applications en tant qu'images de menu fixe ?
UPD du 07.2019 : https://stackoverflow.com/a/57145029/907576
En prenant comme exemple d'application simple de démarrage à ressort (avec un seul noeud final REST), j'ai pu jusqu'à présent trouver les solutions suivantes (considérant que l'application est située à build/libs/spring-boot-demo.jar
avant la construction de Docker:
chemin Jedi si nous voulons utiliser la distribution officielle Oracle OpenJDK sur une version stable et mince de Linux (Debian 9 "Stretch"
pour l'instant):
debian:stretch-slim
(dernière stable) image de baseuse construction multi-étapes de Docker
Première étape de construction de Docker:
Oracle OpenJDK
sur la première étape de construction de Dockerjlink
Deuxième étape de construction de Docker:
Ainsi, final Dockerfile
ressemble à ceci
( actualise JDK VERSION
, URL
et HASH
valeur ):
# 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" ]
Remarque :
Java.base,Java.sql,Java.naming,Java.desktop,Java.management,Java.security.jgss,Java.instrument
). Je les ai trouvés "manuellement" en exécutant l'application et en corrigeant ClassNotFoundException
. En attente de quelques autres recommandations/guides pour les développeurs Spring Boot que Java modules à inclure et quand, tout comme la suppression de dépendances redondantes, comme Java.desktop
, qui ne semble être utilisé que pour PropertyEditorSupport
si vous avez peur de rater certains modules, ils sont assez légers et donnent tous ensemble une taille croissante de 2 Mo. Obtenez une liste complète de Java.*
et jdk.*
11 modules:
Java --list-modules | grep -E "^Java\.[^@]*" | cut -d @ -f 1
Java --list-modules | grep -E "^jdk\.[^@]*" | cut -d @ -f 1
La taille de l'image résultante dans mon cas était de 123 Mo avec un minimum de 7 modules Spring Boot et de 125 Mo avec tous les modules Java.*
Comme amélioration optionnelle de ce workflow de construction :
Moyen facile avec les distributions Open JDK du fournisseur :
En face de Oracle Zulu JDK 11 d’Azul prend en charge port alpin et possède une base respective image Docker .
Ainsi, si Zulu JVM/JDK est respecté, la construction de Docker est beaucoup plus simple:
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" ]
L'image résultante est 73 Mo , comme prévu avec les distributions Alpine démolies.
Au 07.2019
( Note : la première image peut être aussi grosse que : on peut utiliser debian/ubuntu/peu importe et inclure git/gradle/peu importe - cela n'influencera pas la taille finale de l'image résultante, qui est entièrement basée sur la dernière (seconde) étape)
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"]
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"]
Lisez également https://blog.gilliard.lol/2018/11/05/Alpine-jdk11-images.html
Basé sur la réponse de radistao (des trucs cool!), J'ai créé un image basée sur Amazon Corretto JDK11 . Il est également disponible sur DockerHub .
Le minimum maslick/minimalka: jdk11 L’image corretto est ~ 108MB (55MB compressé sur Dockerhub).
Si vous ajoutez un simple fichier Springboot à celui-ci, l’image obtenue sera ~ 125 Mo (71 Mo compressé sur Dockerhub):
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