Reduzindo o tamanho de uma imagem do Docker com um aplicativo de inicialização por mola

Boa tarde


Recentemente, enfrentei a tarefa de iniciar aplicativos de boot 2 da primavera em um cluster kubernetes usando uma imagem do docker. Esse problema não é novo, encontrei rapidamente exemplos no Google e empacotei meu aplicativo. Fiquei muito surpreso ao não encontrar a imagem alpina do jdk11 e esperava que o fino fosse pequeno o suficiente, mas quando enviei a imagem para o registro do docker, notei que seu tamanho era quase 422 megabytes. Sob o gato, há uma descrição de como reduzi a imagem do docker com minha bota de mola e java de 11 a 144 megabytes.



App


Como mencionei anteriormente, meu aplicativo é criado usando a inicialização por mola 2 e é um wrapper da API REST sobre um banco de dados relacional (usando @RepositoryRestResource). Minhas dependências incluem:


org.springframework.boot:spring-boot-starter-data-rest org.springframework.boot:spring-boot-starter-data-jpa org.flywaydb:flyway-core org.postgresql:postgresql 

O arquivo jar coletado tem um tamanho de 37,6 megabytes.


Dockerfile:


 FROM openjdk:11-jdk-slim WORKDIR /home/demo ARG REVISION COPY target/spring-boot-app-${REVISION}.jar app.jar ENTRYPOINT ["java","-jar","app.jar"] 

Como resultado da montagem, recebo uma imagem de tamanho: 422 mb de acordo com a saída do comando docker images. Curiosamente, ao usar a imagem 8-jdk-slim desatualizada, o tamanho é reduzido para 306 mb.


Tentativa 1: Outra imagem básica


O primeiro passo lógico foi uma tentativa de encontrar uma imagem mais leve, preferencialmente baseada em alpinos. Examinei os repositórios Java mais populares:



(11 como a versão atual do LTS e 8 como ainda há um número suficiente de aplicativos que não puderam migrar para versões mais modernas)


Uma tabela com imagens e tags (~ 2700), seus tamanhos no momento da escrita, está disponível aqui


Aqui estão alguns deles:


 openjdk 8 488MB openjdk 8-slim 269MB openjdk 8-alpine 105MB openjdk 8-jdk-slim 269MB openjdk 8-jdk-alpine 105MB openjdk 8-jre 246MB openjdk 8-jre-slim 168MB openjdk 8-jre-alpine 84.9MB openjdk 11 604MB openjdk 11-slim 384MB openjdk 11-jdk 604MB openjdk 11-jdk-slim 384MB openjdk 11-jre 479MB openjdk 11-jre-slim 273MB adoptopenjdk/openjdk8 alpine 221MB adoptopenjdk/openjdk8 alpine-slim 89.7MB adoptopenjdk/openjdk8 jre 200MB adoptopenjdk/openjdk8 alpine-jre 121MB adoptopenjdk/openjdk11 alpine 337MB adoptopenjdk/openjdk11 alpine-slim 246MB adoptopenjdk/openjdk11 jre 218MB adoptopenjdk/openjdk11 alpine-jre 140MB 

Portanto, se você alterar a imagem base para adoptopenjdk / openjdk11: alpine-jre, poderá reduzir a imagem com o aplicativo para 177 mb.


Tentativa 2: tempo de execução personalizado


Desde o lançamento do jdk9 e da modularização, tornou-se possível criar seu próprio tempo de execução que contém apenas os módulos necessários para o seu aplicativo. Você pode ler mais sobre esta funcionalidade aqui .


Vamos tentar determinar os módulos necessários para o aplicativo de inicialização da mola de teste:


 ~/app ᐅ jdeps -s target/app-1.0.0.jar app-1.0.0.jar -> java.base app-1.0.0.jar -> java.logging app-1.0.0.jar -> not found 

Ok, parece que o jdeps não pode lidar com o fat-jar criado com o spring boot, mas podemos descompactar o arquivo e escrever o caminho de classe:


 ~/app ᐅ jdeps -s -cp target/app-1.0.0/BOOT-INF/lib/*.jar target/app-1.0.0.jar.original Error: byte-buddy-1.9.12.jar is a multi-release jar file but --multi-release option is not set ~/app ᐅ jdeps -s --multi-release 11 -cp target/app-1.0.0/BOOT-INF/lib/*.jar target/app-1.0.0.jar.original Error: aspectjweaver-1.9.2.jar is not a multi-release jar file but --multi-release option is set 

Nesta ocasião, um bug está aberto no momento: https://bugs.openjdk.java.net/browse/JDK-8207162


Tentei fazer o download do jdk12 para obter essas informações, mas o seguinte erro ocorreu:


 Exception in thread "main" com.sun.tools.classfile.Dependencies$ClassFileError ... Caused by: com.sun.tools.classfile.ConstantPool$InvalidEntry: unexpected tag at #1: 53 

Por tentativa, erro e pesquisa de módulo por ClassNotFoundException, determinei que meu aplicativo precisa dos seguintes módulos:


  • java.base
  • java.logging
  • java.sql
  • java.naming
  • java.management
  • java.instrument
  • java.desktop
  • java.security.jgss

O tempo de espera para eles pode ser coletado usando:


 jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.logging,java.sql,java.naming,java.management,java.instrument,java.desktop,java.security.jgss --output /usr/lib/jvm/spring-boot-runtime 

Vamos tentar criar uma imagem básica do docker usando estes módulos:


 FROM openjdk:11-jdk-slim RUN jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.logging,java.sql,java.naming,java.management,java.instrument,java.desktop,java.security.jgss --output /usr/lib/jvm/spring-boot-runtime FROM debian:stretch-slim COPY --from=0 /usr/lib/jvm/spring-boot-runtime /usr/lib/jvm/spring-boot-runtime RUN ln -s /usr/lib/jvm/spring-boot-runtime/bin/java /usr/bin/java 

e colecione:


 docker build . -t spring-boot-runtime:openjdk-11-slim 

Como resultado, o tamanho era de 106 megabytes, o que é significativamente menor do que a maioria das imagens de base encontradas com o openjdk. Se você o usar no meu aplicativo, o tamanho resultante será 144 megabytes.


Além disso, podemos usar o spring-boot-runtime:openjdk-11-slim como a imagem base para todos os aplicativos de inicialização do Spring se eles tiverem dependências semelhantes. No caso de várias dependências, é possível usar um conjunto de imagens de vários estágios para cada um dos aplicativos em que o Java Runtime será coletado no primeiro estágio, e o arquivo com o aplicativo será adicionado no segundo.


 FROM openjdk:11-jdk-slim RUN jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,YOUR_MODULES --output /usr/lib/jvm/spring-boot-runtime FROM debian:stretch-slim COPY --from=0 /usr/lib/jvm/spring-boot-runtime /usr/lib/jvm/spring-boot-runtime WORKDIR /home/demo ARG REVISION COPY target/app-${REVISION}.jar app.jar ENTRYPOINT ["/usr/lib/jvm/spring-boot-runtime/bin/java","-jar","app.jar"] 

Conclusão


Atualmente, a maioria das imagens de janela de encaixe para java possui um volume grande o suficiente, o que pode afetar negativamente a hora de início do aplicativo, especialmente se as camadas necessárias ainda não estiverem no servidor. Usando tags com jre ou usando modularização java, é possível criar seu próprio tempo de execução, o que reduzirá significativamente o tamanho da imagem do aplicativo.

Source: https://habr.com/ru/post/pt457476/


All Articles