---
title: "Réduire la taille de ses images Docker avec jlink"
date: 2019-10-04T09:09:18.000Z
canonical: https://www.ekino.fr/publications/reduire-la-taille-de-ses-images-docker-avec-jlink/
---

## Ce que l’on fait déjà depuis longtemps

Il n’est pas nécessaire d’avoir un JDK complet dans la majorité des cas. Une image de base contenant uniquement un JRE est largement suffisante et bien plus petite. Par exemple pour une JVM 11 :
`openjdk:11-jre-slim` : 204 Mo
`openjdk:11-jdk-slim` : 401 Mo

On passe du **simple au double** ! Ici pas de débat on choisit l’image avec un JRE.

Utiliser un JRE nous permet de ne pas avoir tous les outils de développement du JDK que nous n'utilisons de toute façon jamais dans nos images de production. Mais on peut aller plus loin.

## Faire mieux

Rappel : depuis Java 9, le JDK est modulaire (JPMS). L’un des avantages de cette modularité est de pouvoir construire son propre exécutable java contenant uniquement les modules qu’on utilise vraiment. Ceci se fait via l’outil [jlink](https://docs.oracle.com/en/java/javase/11/tools/jlink.html).

La construction de notre image allégée va se faire en 2 temps (merci [Docker multi-stage](https://docs.docker.com/develop/develop-images/multistage-build/)).

### Première étape : créer un exécutable java réduit

`FROM adoptopenjdk/openjdk11:jdk-11.0.4_11 as builder
RUN jlink
--add-modules java.security.jgss,java.rmi,java.sql,java.desktop,jdk.crypto.ec,jdk.unsupported
--verbose
--strip-debug
--compress 2
--no-header-files
--no-man-pages
--output /opt/jre-minimal`

On part d’une image debian contenant un JDK 11. La difficulté est de déterminer de quels modules on a besoin pour notre application. Dans cet exemple il s’agit d’une application web Play 2.6 en Scala 2.12.

Je n’ai pas trouvé de solution miracle. L’outil [jdeps](https://docs.oracle.com/en/java/javase/11/tools/jdeps.html#GUID-A543FEBE-908A-49BF-996C-39499367ADB4) pourrait potentiellement aider mais l’outil est, selon moi, assez cryptique et pas franchement user friendly. Plus d’infos [ici](https://blog.codefx.org/tools/jdeps-tutorial-analyze-java-project-dependencies/) si vous voulez vous y essayer.

Dans cet exemple, on doit ajouter `jdk.unsupported` car [akka](https://github.com/akka/akka) utilise la classe Unsafe. Idem pour `java.sql`, akka utilise sql.Date… alors que cette application ne fait pas du tout de sql. Mais pourquoi donc `java.desktop` me diriez vous ? Et bien tout simplement parce que le package [java.beans](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/beans/package-summary.html) est dedans ! Celui-ci est par exemple utilisé par Google Guice. Pour plus de détails : [https://stackoverflow.com/a/49802687.](https://stackoverflow.com/questions/49784240/java-beans-introspector-requires-desktop-module/49802687#49802687)

### Deuxième étape : créer l’image de run

`FROM debian:stable-slim
MAINTAINER ekino
COPY --from=builder /opt/jre-minimal /opt/jre-minimal
ENV PATH=${PATH}:/opt/jre-minimal/bin
ADD build/distributions/ekino-tools-version.tar /play/
EXPOSE 8080
ARG JAVA_OPTS
ENV JAVA_OPTS=${JAVA_OPTS}
CMD java ${JAVA_OPTS}
-Dhttp.port=8080
-classpath /play/ekino-tools-version/lib/ekino-tools-version.jar play.core.server.ProdServerStart`

On part cette fois d’une image debian-slim qui fait 69 Mo. Il y a sans doute moyen de faire plus petit mais c’est déjà une bonne base. On copie ensuite notre exécutable java construit dans le stage précédent. Enfin, on ajoute les instructions habituelles.

## Bilan

Le gain est très intéressant : on passe d’une image finale de 263 Mo (avec une base JRE) à une image de 180 Mo ! Ceci sans rien changer à notre CI ou configuration de run.

Le repo du projet d’exemple : [https://github.com/ekino/ekino-tools-version](https://github.com/ekino/ekino-tools-version)
