[DOCKER] Comment réduire les images Java

Cet article utilise une application ** Java ** basée sur ** Spring Boot ** comme exemple pour vous donner quelques conseils courants pour réduire les images ** Java **.

Contexte

Avec la diffusion de la technologie des conteneurs, les applications basées sur les conteneurs se multiplient. Les conteneurs sont beaucoup utilisés, mais la plupart des utilisateurs de conteneurs ignorent peut-être le problème simple mais important de la taille de l'image du conteneur. Cet article décrit brièvement la nécessité de simplifier les images de conteneurs et présente quelques astuces courantes pour réduire les images Java, en utilisant les applications Java basées sur Spring Boot comme exemple.

Besoin de simplifier l'image du conteneur

La simplification de l'image du conteneur est très nécessaire. Nous en parlerons à la fois en termes de sécurité et d'agilité.

À propos de la sécurité

En supprimant les composants inutiles de l'image, vous pouvez réduire la surface d'attaque et les risques de sécurité. Dans Docker, vous pouvez utiliser Seccomp pour restreindre les opérations à l'intérieur du conteneur ou utiliser App Armor. Vous pouvez également utiliser //docs.docker.com/engine/security/apparmor/?spm=a2c65.11461447.0.0.4c817eccQzbPjk) pour définir la politique de sécurité de votre conteneur. Cependant, vous devez maîtriser le domaine de la sécurité pour les utiliser.

Agilité

En simplifiant l'image du conteneur, vous pouvez accélérer le déploiement du conteneur. Supposons que vous ayez une soudaine explosion de trafic d'accès et que vous deviez augmenter le nombre de conteneurs pour gérer l'augmentation soudaine de la pression. Si certains hôtes ne contiennent pas l'image cible, vous devez d'abord extraire l'image, puis démarrer le conteneur. Dans ce cas, vous pouvez accélérer le processus et raccourcir la période de mise à l'échelle en réduisant l'image. De plus, des images plus petites peuvent être créées plus rapidement, ce qui économise les coûts de stockage et de transmission.

Conseils courants

Pour conteneuriser votre application Java, procédez comme suit:

  1. Compilez le code source Java et générez un package JAR.
  2. Déplacez le package JAR et les dépendances JAR tierces vers l'emplacement approprié. L'exemple utilisé dans cette section est une application Java basée sur Spring Boot spring-boot-docker est. Le [dockerfile] non optimisé (https://github.com/brucewu-fly/spring-boot-docker/blob/master/dockerfiles/avoid/Dockerfile) utilisé dans cet exemple est:
FROM maven:3.5-jdk-8
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package
ENTRYPOINT ["java","-jar","/usr/src/app/target/spring-boot-docker-1.0.0.jar"]

L'application a été créée à l'aide de Maven et maven: 3.5.5-jdk-8 est spécifié comme image de base du fichier docker. La taille de cette image est de 635 Mo. La taille de l'image finale créée par cette méthode est assez grande à 719 Mo. La raison en est que l'image de base est volumineuse et que Maven télécharge de nombreux packages JAR pour créer l'image finale.

Construction en plusieurs étapes

Seul le Java Runtime Environment (JRE) est requis pour exécuter les applications Java. Aucun outil de compilation, de débogage ou d'exécution Maven ou Java Development Kit (JDK) n'est requis. Par conséquent, une méthode d'optimisation simple consiste à séparer l'image créée en compilant le code source Java de l'image exécutant l'application Java. Pour ce faire, vous devez gérer deux fichiers dockerfile avant la sortie de Docker 17.05, ce qui ajoute à la complexité de la construction de l'image. À partir de Docker 17.05, la fonction Construction à plusieurs étages autorise plusieurs éléments dans un fichier Docker. Vous pouvez maintenant utiliser l'instruction FROM de. Vous pouvez spécifier une image de base différente pour chaque instruction FROM et démarrer un tout nouveau processus de création d'image. Vous pouvez choisir de copier le produit de l'étape précédente de création d'image vers une autre étape et ne laisser que ce dont vous avez besoin dans l'image finale. Le [dockerfile] optimisé (https://github.com/brucewu-fly/spring-boot-docker/blob/master/dockerfiles/multi-stage/Dockerfile?spm=a2c65.11461447.0.0.4c817eccQzbPjk) est ci-dessous Ce sera comme.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:8-jre
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

Le dockerfile utilise maven: 3.5-jdk-8 comme image de construction pour la première étape et ʻopenjdk: 8-jrecomme image de base pour exécuter les applications Java. Seul le fichier.class` compilé dans la première étape est copié dans l'image finale avec les dépendances du JAR tiers. À la suite de l'optimisation, la taille de l'image a été réduite à 459 Mo.

Utilisez une image sans distraction comme image de base

L'image finale est plus petite en raison de la construction en plusieurs étapes, mais 459 Mo est encore trop grand. À la suite d'une analyse approfondie, il a été constaté que la taille de la base ʻopenjdk: 8-jre` est de 443 Mo, ce qui est trop grand. Par conséquent, lors de la prochaine étape d'optimisation, nous avons décidé de réduire la taille de l'image de base.

Le projet open source de Google Distroless a été développé pour résoudre ce problème. L'image Distroless contient uniquement l'application et ses dépendances d'exécution. Ces images n'incluent pas Package Manager, Shell ou tout autre programme que vous attendez d'une distribution Linux standard. Actuellement, Distroless est Java, [Python](https :: //github.com/GoogleContainerTools/distroless/blob/master/experimental/python2.7/README.md?spm=a2c65.11461447.0.0.4c817eccQzbPjk&file=README.md), [Node.js](https: // github. com / GoogleContainerTools / distroless / blob / master / experimental / nodejs / README.md? spm = a2c65.11461447.0.0.4c817eccQzbPjk & file = README.md), .NET /master/experimental/dotnet/README.md?spm=a2c65.11461447.0.0.4c817eccQzbPjk&file=README.md) Fournit une image de base pour les applications qui fonctionnent dans des environnements tels que.

Le fichier dockerfile utilisant l'image Distroless est le suivant Ce sera comme.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM gcr.io/distroless/java
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

La seule différence entre ce dockerfile et le précédent est que l'image de base pour exécuter l'application est passée de ʻopenjdk: 8-jre(443 Mo) àgcr.io / distroless / java` (119 Mo). C'est. Le résultat est une taille d'image finale de 135 Mo.

Le seul inconvénient de l'utilisation d'une image sans distraction est que l'image ne contient pas de coquille. Vous ne pouvez pas utiliser docker attach pour attacher et déboguer des entrées standard, des sorties standard et des erreurs standard (ou des combinaisons de ces trois) de votre application à un conteneur en cours d'exécution. L '[image de débogage] sans distroles (https://github.com/GoogleContainerTools/distroless?spm=a2c65.11461447.0.0.4c817eccQzbPjk#debug-images) fournit un shell busybox. Cependant, je dois reconditionner cette image et déployer le conteneur, ce qui n'est pas utile pour les conteneurs déployés sur la base d'images non déboguées. Du point de vue de la sécurité, cela peut être un avantage car un attaquant ne peut pas attaquer via le shell.

Utiliser l'image alpine comme image de base

Si vous avez besoin d'utiliser le docker attach et que vous souhaitez réduire la taille de l'image, vous pouvez utiliser une image Alps comme image de base. Alpine L'image est incroyablement petite et la taille de l'image de base n'est que d'environ 4 Mo.

Dockerfile utilisant des images alpines est le suivant Sera.

FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package

FROM openjdk:8-jre-alpine
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

ʻOpenjdk: 8-jre-alpine` est construit sur alpine et inclut le runtime Java. La taille de l'image créée avec ce fichier docker est de 99,2 Mo, ce qui est plus petit que l'image créée sur la base de l'image sans distraction.

Pour attacher à un conteneur en cours d'exécution, exécutez la commande docker exec -ti <container_id> sh.

Comparaison de Distroless et Alpine

Distroless et Alpine peuvent fournir de très petites images de base. Lequel dois-je utiliser dans un environnement de production? Si la sécurité est votre priorité absolue, sans distroless est recommandé car les applications packagées ne peuvent exécuter que des fichiers binaires. Si vous appréciez la taille de l'image, nous vous recommandons alpin.

Autres conseils

En plus des conseils ci-dessus, vous pouvez encore simplifier la taille de l'image en effectuant les opérations suivantes.

  1. Combinez plusieurs instructions du fichier docker en une seule. Cela réduit le nombre de couches dans l'image et réduit la taille de l'image.
  2. Placez un contenu volumineux et stable en bas de l'image et un contenu petit et souvent changeant en haut. Vous ne pouvez pas réduire directement la taille de l'image avec cette méthode. Cependant, il tire pleinement parti du mécanisme de cache d'images pour accélérer la création d'images et le déploiement de conteneurs. Pour obtenir des conseils sur l'optimisation des fichiers Dockerfiles, consultez Bonnes pratiques pour l'écriture de fichiers Docker (https://docs.docker.com/develop/develop-images/dockerfile_best-practices/?spm=a2c65.11461447.0.0.4c817eccQzbPjk )Prière de se référer à.

Aperçu

  1. Grâce à une série d'optimisations, la taille de l'image des applications Java a été réduite de 719 Mo à environ 100 Mo. Si votre application s'exécute dans d'autres environnements, vous pouvez l'optimiser sur une base similaire.
  2. Pour les images Java, un autre outil fourni par Google, jib, automatise le processus complexe de création d'images. Peut être traité et une image Java simplifiée peut être fournie. Avec lui, vous n'avez pas besoin d'écrire un fichier docker ni même d'installer Docker.
  3. Pour les conteneurs tels que distro-less qui ne sont pas pratiques pour le débogage, si vous enregistrez le journal de manière centralisée, il sera plus facile de suivre et de résoudre les problèmes. Pour plus d'informations, consultez l'article sur les meilleures pratiques techniques pour la journalisation des conteneurs.

Recommended Posts

Comment réduire les images Java
[rails] Comment publier des images
Comment abaisser la version java
[Java] Comment utiliser Map
Comment désinstaller Java 8 (Mac)
Java - Comment créer JTable
Comment gérer les images téléchargées
Comment rédiger un commentaire java
Comment utiliser la classe Java
[Java] Comment utiliser removeAll ()
[Java] Comment afficher les Wingdings
Comment utiliser Java Map
Comment définir des constantes Java
Comment utiliser les variables Java
Comment convertir la base Java
[Java] Comment implémenter le multithreading
Comment initialiser un tableau Java
Comment étudier Java Silver SE 8
Comment utiliser HttpClient de Java (Get)
Étudier Java # 6 (Comment écrire des blocs)
Comment créer un conteneur Java
Comment désassembler un fichier de classe Java
Comment utiliser HttpClient de Java (Post)
[Java] Comment utiliser la méthode de jointure
Comment apprendre JAVA en 7 jours
[Traitement × Java] Comment utiliser les variables
Comment décompiler un fichier de classe Java
[JavaFX] [Java8] Comment utiliser GridPane
Comment écrire une déclaration de variable Java
Comment utiliser les méthodes de classe [Java]
[Java] Comment utiliser List [ArrayList]
Comment utiliser les classes en Java?
Comment nommer des variables en Java
Comment passer Oracle Java Silver
Comment activer Iterator Dojo (Java)
java Eclips Comment déboguer javaScript
[Traitement × Java] Comment utiliser les tableaux
Comment créer un tableau Java
Comment utiliser les expressions Java lambda
[Java] Comment utiliser la classe Math
Comment trouver les nombres premiers Java
Comment utiliser le type enum Java
Comment concaténer des chaînes avec Java
Comment créer un résumé de calendrier Java
Comment implémenter le calcul de la date en Java
Comment implémenter le filtre de Kalman par Java
Prise en charge multilingue de Java Comment utiliser les paramètres régionaux
Comment compiler Java avec VsCode & Ant
[Rails] Comment télécharger des images à l'aide de Carrierwave
[Java] Comment ajouter des données à la liste (add, addAll)
Comment changer d'images miniatures avec JavaScript
[Java] Comment calculer l'âge à l'aide de LocalDate
Comment faire une conversion de base en Java