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 **.
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.
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é.
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.
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.
Pour conteneuriser votre application Java, procédez comme suit:
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.
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.
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.
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
.
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.
En plus des conseils ci-dessus, vous pouvez encore simplifier la taille de l'image en effectuant les opérations suivantes.
Recommended Posts