Introduction à Docker et Java : pourquoi la conteneurisation transforme le développement
Le développement logiciel moderne est impensable sans la conteneurisation. Docker est devenu le standard de facto pour empaqueter, distribuer et exécuter des applications. Pour les développeurs Java, l'utilisation de Docker résout des problèmes clés : "ça marche sur ma machine" et les difficultés de configuration de l'environnement. Dans cet article, nous allons voir comment conteneuriser des applications Java, d'un simple fichier JAR à un microservice complexe avec Spring Boot.
Docker permet d'isoler une application avec ses dépendances (JVM, bibliothèques, utilitaires système) dans un conteneur léger et portable. C'est particulièrement important pour Java, où la version du JDK, les paramètres mémoire et les bibliothèques système peuvent fortement influencer le comportement du programme.
Ce que vous apprendrez dans cet article
- Création d'un Dockerfile pour les applications Java
- Optimisation de la taille des images
- Travail avec des projets multi-modules Maven/Gradle
- Bonnes pratiques de sécurité et de performance
1. Bases : création d'un Dockerfile pour une application Java
Commençons par un exemple simple. Supposons que vous ayez une application Java compilée en fichier JAR. Voici un Dockerfile minimal qui l'empaquètera dans un conteneur :
# Utilisation de l'image officielle OpenJDK
FROM openjdk:17-jdk-slim
# Définition du répertoire de travail
WORKDIR /app
# Copie du fichier JAR dans le conteneur
COPY target/myapp.jar app.jar
# Ouverture du port écouté par l'application
EXPOSE 8080
# Commande de lancement
ENTRYPOINT ["java", "-jar", "app.jar"]
Ce Dockerfile fait trois choses simples : il prend une image de base avec JDK 17, copie le JAR compilé et l'exécute. Cependant, dans les projets réels, cette approche n'est pas efficace — à chaque modification du code, Docker reconstruit toute l'image, y compris la copie du JAR.
Construction multi-étapes (Multi-stage build)
Pour séparer les étapes de construction et d'exécution, utilisez des Dockerfile multi-étapes. Cela réduit l'image finale en excluant les outils de construction (Maven, Gradle, JDK pour la compilation).
# Étape de construction
FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
# Étape finale
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
La première étape utilise une image Maven complète pour la compilation, la seconde une image JRE minimale pour l'exécution. L'image finale pèse environ 200 Mo au lieu de 700+ Mo.
2. Optimisation des images : réduire la taille et accélérer la construction
Les images volumineuses ralentissent le déploiement et augmentent le temps de chargement. Voici quelques techniques pour Java :
Utilisez JLink pour créer une JRE minimale
Depuis Java 9, vous pouvez créer une JRE personnalisée contenant uniquement les modules nécessaires. Cela réduit radicalement la taille de l'image.
FROM openjdk:17-jdk-slim AS jre-builder
RUN jlink \
--add-modules java.base,java.logging,java.sql \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /jre
FROM debian:bookworm-slim
COPY --from=jre-builder /jre /jre
WORKDIR /app
COPY target/myapp.jar app.jar
ENV PATH="/jre/bin:${PATH}"
ENTRYPOINT ["java", "-jar", "app.jar"]
Une telle image peut peser seulement 40-60 Mo au lieu de 200+ Mo.
Mise en cache des couches Docker
Docker met en cache chaque couche. Pour accélérer la construction, placez les fichiers rarement modifiés (dépendances) au début du Dockerfile, et les fichiers fréquemment modifiés (code source) à la fin.
FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /build
# Copier d'abord uniquement pom.xml et télécharger les dépendances
COPY pom.xml .
RUN mvn dependency:go-offline
# Ensuite copier les sources et compiler
COPY src ./src
RUN mvn clean packag