Docker Multi-Stage para Aplicações JAVA 21
Tags: java, docker, backend, devops
Published: 2024-06-11 15:53:52




Para criar um Dockerfile com dois estágios para uma aplicação Java 21, você pode seguir um processo de multi-stage build. Isso ajuda a **reduzir o tamanho da imagem final** e garante que apenas os artefatos necessários sejam incluídos na imagem final de execução. Vamos seguir um exemplo com 2 estágios:

1. **Primeiro estágio (build)**: Compilar a aplicação usando uma imagem que tenha o **JDK 21**.

2. **Segundo estágio (runtime)**: Criar uma imagem mais leve **apenas com o JRE** para rodar a aplicação.

## Estrutura do projeto
Deixei um projeto bem simples, feito em Spring Boot 3.3.0 que você pode baixar no meu [github](https://github.com/adilsonoj/java-docker-demo), que iremos seguir como exemplo:

```
/meu-projeto
|-- src
|   `-- main
|       `-- java
|           `-- com
|               `-- exemplo
|                   `-- DemoApplication.java
|                   `-- HelloWorldController.java
|-- pom.xml
```

## Exemplo de Dockerfile
Se você baixar o projeto de exemplo, o Dockerfile já existe e você pode apenas acompanhar o artigo, caso esteja com no seu projeto crie um arquivo chamado Dockerfile na raiz do seu projeto:

```Dockerfile
# Etapa 1: Compilar a aplicação
FROM maven:3.9.7-eclipse-temurin-21-alpine AS build

# Define o diretório de trabalho dentro do contêiner
WORKDIR /app

# Copia o arquivo pom.xml e os arquivos de dependências para o diretório de trabalho
COPY pom.xml ./
COPY src ./src

# Compila a aplicação
RUN mvn package

# Etapa 2: Criar a imagem final para execução
FROM eclipse-temurin:21-jre-alpine

# Define o diretório de trabalho dentro do contêiner
WORKDIR /app

# Cria um argumento para o nome da aplicação
ARG JAR_FILE=target/*.jar

# Copia o jar compilado da etapa anterior
COPY --from=build /app/${JAR_FILE} app.jar

# Expõe a porta da aplicação
EXPOSE 8080

# Define o comando padrão para rodar a aplicação
CMD ["java", "-jar", "app.jar"]
```

## Explicação do Dockerfile

1. Primeiro estágio (build):

  - `FROM maven:3.9.7-eclipse-temurin-21-alpine AS build`: Usa uma imagem oficial do Maven base no Eclipse Temurin JDK 21 para compilar a aplicação.
  - `WORKDIR /app`: Define `/app` como o diretório de trabalho.
  - `COPY pom.xml ./` e `COPY src ./src`: Copia os arquivos do projeto para dentro do contêiner.
  - `RUN mvn package`: Compila e cria o artefato da aplicação usando Maven.

2. Segundo estágio (runtime):

  - `FROM eclipse-temurin:21-jre-alpine`: Usa uma imagem oficial do Eclipse Temurin JRE 21 para executar a aplicação, resultando em uma imagem mais leve.
  - `WORKDIR /app`: Define `/app` como o diretório de trabalho.
  - `COPY --from=build /app/target/minha-aplicacao.jar ./minha-aplicacao.jar`: Copia o arquivo JAR compilado da etapa anterior para o diretório de trabalho.
  - `CMD ["java", "-jar", "minha-aplicacao.jar"]`: Define o comando padrão para executar a aplicação.


## Passos para construir e rodar a imagem

1. Construir a imagem:
```shell
docker build -t minha-aplicacao:latest .
```

2. Executar o contêiner:

```shell
docker run -p 8080:8080 minha-aplicacao:latest
```

3. Teste a aplicação:

```shell
GET http://localhost:8080/hello
```

## Vantagens da construção em dois estágios

### Imagens mais leves:

Quando usamos multi-stage builds, a imagem final só contém os artefatos necessários para rodar a aplicação. Isso significa que todas as ferramentas de compilação e dependências de desenvolvimento não são incluídas, resultando em uma **imagem mais leve e eficiente.**

### Segurança melhorada:

Reduzir o número de componentes na imagem final **diminui a superfície de ataque**, melhorando a segurança. Menos dependências e ferramentas significam menos possíveis vulnerabilidades.

### Desempenho otimizado:

Imagens menores são mais rápidas para baixar e iniciar, o que é especialmente importante em ambientes de produção onde a **eficiência** e a **velocidade** são cruciais.

### Separação de responsabilidades:

Dividir o processo em estágios distintos ajuda a manter uma separação clara entre as etapas de construção e execução. Isso facilita a **manutenção** e a **compreensão** do Dockerfile.

### Conclusão

Construir imagens Docker em dois estágios é uma prática poderosa que traz eficiência e simplicidade. Com essa técnica, você cria imagens mais leves, seguras e fáceis de manter. 
Espero que este guia tenha ajudado você a entender melhor essa prática e como implementá-la em seus projetos. Boa sorte e feliz codificação!

Codigo fonte: [github](https://github.com/adilsonoj/java-docker-demo)