Basé sur Java in a World of Containers donné en japonais lors de la tournée Oracle Groundbreakers APAC à Tokyo le 11/13 J'écris.
La figure ci-dessous est un graphique de module de java9 ou version ultérieure.
Lors de l'écriture d'une application en Java, il est rare de tout utiliser dans ce graphe de module. Par exemple, java.xml, corba, javaws sont souvent inutiles.
Si vous créez une image Docker avec Linux et JDK sans y penser avec Docker, elle sera assez volumineuse. Par conséquent, il semble que les conteneurs et java soient souvent considérés comme incompatibles. Grande capacité, lourd, démarrage lent, etc. Pourtant, les fonctionnalités de Java sont également idéales pour les conteneurs. Il existe de nombreux avantages tels que l'autonomie d'exécution, le matériel et le système d'exploitation, la compatibilité de sécurité garantie par JVM, une exécution stable garantie lorsque l'environnement change, l'écosystème et le meilleur choix de conteneurs. .. Un JDK qui est trop lourd par défaut peut être amélioré en modularisant le JDK lui-même avec Jigsaw et en organisant les dépendances.
Dockerfile
Le système d'exploitation crée une image avec ubuntu: latest. Tout d'abord, créez un environnement avec la taille par défaut et essayez Hello World.
Dockerfile
FROM ubuntu:latest
ADD openjdk-11.0.1_linux-x64_bin.tar.gz /opt/jdk/
ADD HelloWorld.class HelloWorld.class
ENV PATH /opt/jdk/jdk-11.0.1/bin:$PATH
CMD [ "java", "-showversion", "HelloWorld" ]
Créez et exécutez l'image.
$ docker build -t helloworld-java .
$ docker run --rm helloworld-java
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
Hello World!
Jetons un coup d'œil à l'image créée.
$ docker images helloworld-java
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld-java latest 682ae9922b5b 2 minutes ago 396MB
Il y a environ 400 Mo.
Créez un JRE personnalisé à l'aide de jdeps et jlink. Vous pouvez voir les dépendances du module en utilisant jdeps. Jetons un coup d'œil au module Hello World.
$ jdeps --list-deps HelloWorld.class
java.base
Le contenu étant Hello World, il existe peu de dépendances. Au niveau HelloWorld, il semble que seul le module java.base soit utilisé.
Créons un JRE personnalisé avec jlink.
jlink --compress=2 --module-path $JAVA_HOME/jmods --add-modules java.base --output jre-min
Seul java.base est utilisé, donc add-modules seul est spécifié. Après l'exécution, jre-min est créé. Dans cet environnement, Hello World est le minimum requis pour s'exécuter. La capacité était également de 27 Mo.
python
.
├── Dockerfile
├── HelloWorld.class
├── HelloWorld.java
├── hello.jar
├── jre-min
│ ├── bin
│ │ ├── java
│ │ └── keytool
│ ├── conf
│ │ ├── net.properties
│ │ └── security
│ │ ├── java.policy
│ │ ├── java.security
│ │ └── policy
│ │ ├── README.txt
│ │ ├── limited
│ │ │ ├── default_US_export.policy
│ │ │ ├── default_local.policy
│ │ │ └── exempt_local.policy
│ │ └── unlimited
│ │ ├── default_US_export.policy
│ │ └── default_local.policy
│ ├── include
│ │ ├── classfile_constants.h
│ │ ├── darwin
│ │ │ └── jni_md.h
│ │ ├── jni.h
│ │ ├── jvmti.h
│ │ └── jvmticmlr.h
│ ├── legal
│ │ └── java.base
│ │ ├── COPYRIGHT
│ │ ├── LICENSE
│ │ ├── aes.md
│ │ ├── asm.md
│ │ ├── c-libutl.md
│ │ ├── cldr.md
│ │ ├── icu.md
│ │ ├── public_suffix.md
│ │ └── unicode.md
│ ├── lib
│ │ ├── classlist
│ │ ├── jli
│ │ │ └── libjli.dylib
│ │ ├── jrt-fs.jar
│ │ ├── jspawnhelper
│ │ ├── jvm.cfg
│ │ ├── libjava.dylib
│ │ ├── libjimage.dylib
│ │ ├── libjsig.dylib
│ │ ├── libnet.dylib
│ │ ├── libnio.dylib
│ │ ├── libosxsecurity.dylib
│ │ ├── libverify.dylib
│ │ ├── libzip.dylib
│ │ ├── modules
│ │ ├── security
│ │ │ ├── blacklisted.certs
│ │ │ ├── cacerts
│ │ │ ├── default.policy
│ │ │ └── public_suffix_list.dat
│ │ ├── server
│ │ │ ├── Xusage.txt
│ │ │ ├── libjsig.dylib
│ │ │ └── libjvm.dylib
│ │ └── tzdb.dat
│ └── release
└── openjdk-11.0.1_linux-x64_bin.tar.gz
Lançons Hello World dans cet environnement minimal.
$ jre-min/bin/java -showversion HelloWorld
java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)
Hello World!
Créons un JRE personnalisé avec jlink et construisons-le.
Dockerfile
FROM ubuntu:latest AS build
ADD openjdk-11.0.1_linux-x64_bin.tar.gz /opt/jdk/
ENV PATH /opt/jdk/jdk-11.0.1/bin:$PATH
RUN ["jlink", "--compress=2", "--module-path", "/opt/jdk/jdk-11/jmods", "--add-modules", "java.base", "--output", "/linked"]
FROM ubuntu:latest
COPY --from=build /linked /opt/jdk/
ENV PATH=$PATH:/opt/jdk/bin
ADD HelloWorld.class /
CMD [ "java", "-showversion", "HelloWorld" ]
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld-java latest e71329542c40 2 minutes ago 123MB
$ docker run -it helloworld-java
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
Hello World!
La taille est inférieure au quart de la précédente.
Nous avons le Java minimum requis, mais nous avons toujours 123 Mo. Si seule la méthode est utilisée plus tôt, seul Java peut être allégé, nous allons donc également modifier le système d'exploitation. Si vous voulez simplement exécuter ava, ubuntu est trop luxueux. Par conséquent, utilisez alpine linux pour créer l'environnement Linux minimum requis. alpine est un Linux léger basé sur musl libc et BusyBox (il ne contient vraiment rien ...). La configuration minimale semble être plus légère que 5 Mo. Reportez-vous à Dockerfile de l'environnement Java basé sur les Alpes publié par AdoptOpenJDK Créez une image avec la configuration minimale.
Dockerfile
FROM adoptopenjdk/openjdk11:alpine-slim AS jlink
RUN ["jlink", "--compress=2", \
"--module-path", "/opt/java/openjdk/jmods", \
"--add-modules", "java.base", \
"--output", "/jlinked"]
FROM alpine
RUN apk --update add --no-cache ca-certificates curl openssl binutils xz \
&& GLIBC_VER="2.28-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-8.2.1%2B20180831-1-x86_64.pkg.tar.xz" \
&& GCC_LIBS_SHA256=e4b39fb1f5957c5aab5c2ce0c46e03d30426f3b94b9992b009d417ff2d56af4d \
&& ZLIB_URL="https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.9-1-x86_64.pkg.tar.xz" \
&& ZLIB_SHA256=bb0959c08c1735de27abf01440a6f8a17c5c51e61c3b4c707e988c906d3b7f67 \
&& curl -Ls https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub \
&& curl -Ls ${ALPINE_GLIBC_REPO}/${GLIBC_VER}/glibc-${GLIBC_VER}.apk > /tmp/${GLIBC_VER}.apk \
&& apk add /tmp/${GLIBC_VER}.apk \
&& curl -Ls ${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 -Ls ${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 binutils \
&& rm -rf /tmp/${GLIBC_VER}.apk /tmp/gcc /tmp/gcc-libs.tar.xz /tmp/libz /tmp/libz.tar.xz /var/cache/apk/*
COPY --from=jlink /jlinked /opt/jdk/
ADD HelloWorld.class /
CMD ["/opt/jdk/bin/java", "-showversion", "HelloWorld"]
$ docker build -t helloworld-java .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworld-java latest 407614883e2b 38 seconds ago 52.1MB
C'est moins de la moitié du précédent. C'est environ 1/8 de l'original.
Bien sûr, il peut être exécuté
$ docker run -it helloworld-java
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.1+13)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.1+13, mixed mode)
Hello World!
Il semble que l'on dise souvent que le conteneur et le java sont incompatibles l'un avec l'autre en raison de leur grande capacité, de leur poids élevé et de leur démarrage lent. Après JDK9, vous pouvez créer un environnement dédié avec jdeps et jlink. Puisqu'il est possible de créer l'environnement minimum nécessaire, il est possible de créer un conteneur léger. En modifiant le système d'exploitation, vous pouvez créer un environnement encore plus léger et que vous aimez.