Aller au contenu
DockerJavaBackCloud

Utilisation de JLink pour créer des images plus performantes pour vos applications Java

Réduire la taille de vos images Docker peut significativement améliorer le temps de démarrage et les performances de déploiement. En utilisant JLink, un outil permettant de créer une JRE personnalisée contenant uniquement les modules nécessaires, vous pouvez optimiser vos images Docker.

Comment optimiser vos images Docker

La conteneurisation a introduit plus de flexibilité et d'agilité dans le développement logiciel moderne. Ceci a permis de créer et de déployer des applications dans des conteneurs légers et isolés, mais qui exposent parfois des failles de sécurité pouvant être exploitées pour corrompre notre environnement. Réduire le nombre d'artefacts dans une image permet de réduire les risques en diminuant la surface d'attaque pour les acteurs malveillants.

Dans cet article, nous allons explorer comment générer des images Docker avec JLink pour créer des images de taille réduite.

Introduction à JLink

JLink est un outil introduit avec la JDK 9 qui permet de créer des runtimes Java personnalisés et optimisés en assemblant uniquement les modules et les dépendances requis par l'application, réduisant ainsi la taille du runtime et améliorant les performances.

Avantages apporté par JLink dans la construction d'images Dockers

La taille de l'image reste toujours un point d'attention à prendre en compte, surtout avec les applications Spring Boot qui ramènent, dans leur sillage, toutes leurs dépendances. Une image de grande taille aura un temps de démarrage important, coûtera plus cher en termes de stockage et aura un temps de déploiement plus long sur un orchestrateur de conteneurs tel que K8s.

En réduisant la taille de l'image en incluant uniquement les modules Java nécessaires, vous pourrez optimiser les performances et améliorer significativement la sécurité.

Étapes pour créer une image allégée d'une application Spring Boot Java avec JLink

  1. Déterminer les dépendances
    La première étape consiste à utiliser JDeps pour déterminer les dépendances de l'application :
jdeps --ignore-missing-deps --recursive --print-module-deps  my-app-0.0.1.jar
  1. Créer un JDK personnalisé avec Jlink
    Utilisez les modules détectés dans l'étape précédente pour créer un JDK personnalisé avec JLink :
jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.logging --output my-custom-jdk
Dans cet exemple, notre application my-app dépend uniquement de java.base et java.logging

Créer un fichier Dockerfile
Pour créer l'image, nous allons écrire un Dockerfile multi-étapes qui utilisera les étapes décrites ci-dessus pour déterminer les dépendances, créer un JRE personnalisé, et finalement l'utiliser pour créer l'image finale :

# Image de base avec le JDK pour la construction
FROM maven:3-eclipse-temurin-17 as build
# Construire le workspace
RUN mkdir /usr/src/myapp
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp

# Créer mon application
RUN mvn package -DskipTests

# Défaire le jar
RUN jar xf target/my-app.jar

# Déterminer les dépendences
RUN jdeps --ignore-missing-deps -q  \
    --recursive  \
    --multi-release 17  \
    --print-module-deps  \
    --class-path 'BOOT-INF/lib/*'  \
    target/my-app.jar > deps.info

# Création du JRE custom
RUN jlink \
    --add-modules $(cat deps.info) \
    --strip-debug \
    --compress 2 \
    --no-header-files \
    --no-man-pages \
    --output /my-custom-jre

# Créer l'image finale
FROM debian:bookworm-slim
# Définir JAVA_HOME
ENV JAVA_HOME /user/java/jdk17
ENV PATH $JAVA_HOME/bin:$PATH

# Copier le JDK personnalisé de l'étape précédente
COPY --from=build /my-custom-jre $JAVA_HOME

# Copier l'application Spring Boot jar
RUN mkdir /workspace
COPY --from=build /usr/src/myapp/target/my-app.jar /workspace/
WORKDIR /workspace

# Définir le point d'entrée
ENTRYPOINT ["java", "-jar", "/workspace/my-app.jar"]

Conclusion

Utiliser JLink pour créer un JDK personnalisé permet d'optimiser nos images Docker, de réduire leur taille et d'améliorer les performances, ce qui est particulièrement bénéfique pour les déploiements cloud où l'optimisation des ressources et des coûts est cruciale.

Dernier