Docker et Java : conteneurisation avancée d'applications

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Docker et Java : niveau avancé de conteneurisation d'applications

\n\n

La conteneurisation d'applications Java est devenue un standard de facto dans le développement moderne. Cependant, une connaissance de base de Docker (création d'une image à partir de openjdk:11 et lancement d'un conteneur) ne répond plus aux exigences des environnements de production. À un niveau avancé, il est nécessaire de prendre en compte les particularités du fonctionnement de la JVM à l'intérieur d'un conteneur, d'optimiser la taille des images, de gérer la mémoire et de configurer le monitoring. Dans cet article, nous aborderons les techniques clés qui vous aideront à créer des images Docker efficaces et sécurisées pour les applications Java.

\n\n

1. Construction multi-étapes : minimisation de la taille de l'image

\n\n

L'approche classique « un Dockerfile — une image » conduit souvent à un gonflement de l'artefact final. Les outils de construction (Maven, Gradle, compilateur) se retrouvent dans l'image alors qu'ils ne sont pas nécessaires à l'exécution. La solution est la construction multi-étapes (multi-stage). Nous divisons le processus en étapes : construction (build) et exécution (runtime).

\n\n

Exemple de Dockerfile pour une application Spring Boot utilisant Maven :

\n\n
# Étape de construction\nFROM maven:3.8.6-openjdk-17 AS builder\nWORKDIR /app\nCOPY pom.xml .\nRUN mvn dependency:go-offline -B\nCOPY src ./src\nRUN mvn clean package -DskipTests\n\n# Étape d'exécution\nFROM eclipse-temurin:17-jre-alpine\nWORKDIR /app\nCOPY --from=builder /app/target/*.jar app.jar\nEXPOSE 8080\nENTRYPOINT ["java", "-jar", "app.jar"]
\n\n

En conséquence, l'image finale pèse environ 150 Mo au lieu de 600+ Mo. Important : utilisez des images jre (et non jdk) et des distributions minimales (Alpine, Slim). Pour les applications sur Java 17+, vous pouvez envisager jlink — la création d'une JRE personnalisée avec uniquement les modules nécessaires.

\n\n

2. Configuration de la JVM pour fonctionner à l'intérieur d'un conteneur

\n\n

Pendant longtemps, la JVM n'a pas su déterminer correctement les limites de mémoire et de CPU définies pour le conteneur. À partir de Java 8u191 et Java 10, la prise en charge des cgroups v1 est apparue (et avec Java 15, celle des cgroups v2). Cependant, il ne faut pas se fier uniquement à l'automatisation.

\n\n

Paramètres clés pour la production :

\n
    \n
  • -XX:+UseContainerSupport — active la prise en charge des conteneurs (actif par défaut dans Java 10+).
  • \n
  • -XX:MaxRAMPercentage=75.0 — limite l'utilisation du tas à 75% de la mémoire disponible du conteneur. Cela laisse de la mémoire pour le métaspace, la pile des threads et les processus système.
  • \n
  • -XX:ActiveProcessorCount=2 — indication explicite du nombre de processeurs disponibles, si l'auto-détection échoue.
  • \n
\n\n

Exemple de commande ENTRYPOINT complète :

\n\n
ENTRYPOINT ["java", \\\n    "-XX:+UseContainerSupport", \\\n    "-XX:MaxRAMPercentage=75.0", \\\n    "-XX:+ExitOnOutOfMemoryError", \\\n    "-jar", "app.jar"]
\n\n

Important : évitez les valeurs fixes -Xmx et -Xms dans un environnement Docker. Elles ne s'adaptent pas aux changements de limites du conteneur lors de la réplication ou de la mise à l'échelle.

\n\n

3. Optimisation des couches et mise en cache de la construction

\n\n

Chaque instruction dans un Dockerfile crée une nouvelle couche. Docker met en cache les couches qui n'ont pas changé. Pour accélérer les constructions répétées, placez les instructions des moins changeantes aux plus changeantes.

\n\n

Structure correcte d'un Dockerfile :

\n
    \n
  1. Installation des dépendances OS (apk add, apt-get).
  2. \n
  3. Copie des fichiers de configuration du constructeur (pom.xml, build.gradle).
  4. \n
  5. Téléchargement des dépendances (mvn dependency:go-offline).
  6. \n
  7. Copie du code source.
  8. \n
  9. Construction et copie de l'artefact.
  10. \n
\n\n

Vous pouvez également utiliser le mise en cache des couches Docker dans CI/CD. Par exemple, dans GitHub Actions ou GitLab CI, conservez le cache Maven entre les builds :

\n\n
# Exemple pour GitLab CI\ncache:\n  key: ${CI_COMMIT_REF_SLUG}\n  paths:\n    - .m2/repository/\n    - .gradle/caches/
\n\n

Envisagez également l'utilisation de

Blogs

Book Recommendations