Tuesday, December 18, 2018

Docker: Imagens (muito!) menores com multi-stage-build

Quando se fala em containers no Docker, menos é mais, ou grande significa lento e difícil. Por essa razão, imagens no Docker precisam ser pequenas. A melhor imagem é sempre a menor possível.

É importante perceber que, dependendo da forma como as instruções são colocadas no Dockerfile, a imagem final poderá ser - muito! - maior ou menor.


Multi-stage builds é um novo recurso do Docker disponível a partir da versão 17.05. É uma ferramenta extremamente útil para deixar a imagem que irá rodar aplicação a menor possível. Basicamente, com Multi-Stage Builds nós temos um único Dockerfile com mais de uma instrução FROM. Cada instrução FROM representa um estágio de construção da imagem e pode facilmente copiar artefatos dos estágios anteriores para o atual. Vamos a um exemplo aproveitando um post anterior deste blog.

Diminuindo o tamanho da imagem em 90%

Neste artigo intitulado Hello World Java-Docker, criei uma aplicação java simples e que rodava em container do Docker, sem explorar outros recursos, apenas como uma introdução sobre como rodar o Java no Docker. O arquivo Dockerfile.simple é o que segue:
# constrói uma imagem baseada no openjdk 8
FROM openjdk:8

ADD HelloJavaDocker.class .

ENTRYPOINT ["java", "HelloJavaDocker"]
    
Após gerar o .class pelo comando javac (fora do Docker), construímos a imagem chamada hello-java-docker pelo comando:
$ docker build -f Dockerfile.simple -t hello-java-docker .    
E em seguida criamos o container e rodamos a aplicação:
$ docker run -it hello-java-docker    
A aplicação executa com sucesso dentro da imagem hello-java-docker



Entretanto, ao executar o comando docker images, veremos que a imagem hello-java-docker é incrivelmente grande, possuindo o tamanho de quase 624MB:
rafael@rafael-desktop ~/generalProjects/HelloJavaDocker $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
hello-java-docker   latest              83ce2e26c600        About a minute ago   624MB
openjdk             8                   c14ba9d23b3a        4 weeks ago          624MB
rafael@rafael-desktop ~/generalProjects/HelloJavaDocker $     
Podemos diminuir esse tamanho, alterando o Dockerfile, dividindo a construção da imagem em dois estágios. Afinal, não precisamos de todo ambiente JDK apenas para um Hello World. Precisamos apenas da versão básica da JRE. Então criamos um arquivo chamado Dockerfile.builders com as instruções que seguem:
FROM openjdk:8 AS Builder
ENV APP_HOME=/root/dev/apps/
WORKDIR $APP_HOME
COPY HelloJavaDocker.java $APP_HOME
RUN javac HelloJavaDocker.java


FROM openjdk:8-jre-alpine
WORKDIR root
COPY --from=Builder /root/dev/apps/HelloJavaDocker.class .
ENTRYPOINT ["java", "HelloJavaDocker"]    
  1. A primeira instrução FROM, para a qual demos o alías de Builder, utiliza a imagem openjdk:8.
  2. Criamos uma variável de ambiente com ENV dentro da imagem
  3. Copiamos o arquivo com o código java para APP_HOME
  4. Dessa vez compilamos a classe dentro do container
  5. O próximo FROM cria uma imagem baseada no JRE Linux Alpine
  6. Copiamos o .class gerado em Builder
  7. Executamos a aplicação
Agora, vamos construir uma imagem chamada chamada hello-java-docker-smaller. Em seguida criamos o container:
$ docker build -f Dockerfile.builders -t hello-java-docker-smaller .
$ docker run -it hello-java-docker-smaller    
O resultado da aplicação é o mesmo. Porém ao rodar docker images, veremos que o tamanho da nova imagem hello-java-docker-smaller é de apenas 83MB. Uma queda no tamanho de quase 90%:
rafael@rafael-desktop ~/generalProjects/HelloJavaDocker $ docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
hello-java-docker-smaller   latest              b5daa3a785c1        3 minutes ago       83MB
                                    c1625c3ad04b        3 minutes ago       624MB
hello-java-docker           latest              83ce2e26c600        6 minutes ago       624MB
openjdk                     8                   c14ba9d23b3a        4 weeks ago         624MB
openjdk                     8-jre-alpine        2e01f547f003        7 weeks ago         83MB
rafael@rafael-desktop ~/generalProjects/HelloJavaDocker $ 
    


"Falando novamente ao povo, disse Jesus: “Eu sou a luz do mundo; aquele que me segue, não andará em trevas, mas terá a luz da vida."
Jo 8:12


       

No comments:

Post a Comment