03 Docker com Aplicações Spring Boot - KleberVales/Dominando-Docker GitHub Wiki
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dockerizar uma aplicação Spring Boot significa empacotá-la em um container para facilitar a execução, distribuição e escalabilidade. Isso elimina problemas de compatibilidade e garante que a aplicação rode de forma consistente em qualquer ambiente.
Ter o Docker instalado.
Uma aplicação Spring Boot já construída (geralmente um .jar gerado pelo Maven ou Gradle).
Familiaridade com o terminal.
Após compilar sua aplicação, você terá algo como:
/meu-app
├── target/
│ └── meu-app-0.0.1-SNAPSHOT.jar
├── src/
└── DockerfileO Dockerfile define como a imagem será construída.
Exemplo básico:
# Usando imagem base do OpenJDK
FROM openjdk:17-jdk-slim
# Definindo diretório de trabalho
WORKDIR /app
# Copiando o JAR para dentro do container
COPY target/meu-app-0.0.1-SNAPSHOT.jar app.jar
# Expondo a porta padrão do Spring Boot
EXPOSE 8080
# Comando para rodar a aplicação
ENTRYPOINT ["java", "-jar", "app.jar"]No diretório do projeto, execute:
docker build -t meu-springboot-app:1.0 .-
-t → nome e versão da imagem.
-
. → indica que o Dockerfile está no diretório atual.
docker run -d -p 8080:8080 --name springboot-container meu-springboot-app:1.0-
-p 8080:8080 → mapeia a porta do container para o host.
-
--name → dá um nome ao container.
Agora, acesse no navegador:
http://localhost:8080Para reduzir o tamanho da imagem, podemos usar multi-stage builds:
# Etapa 1: build da aplicação
FROM maven:3.9.6-eclipse-temurin-17 AS build
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests
# Etapa 2: imagem final
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=build /app/target/meu-app-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]Depois de dockerizar, você pode enviar sua imagem para um registry (Docker Hub, GitHub ou AWS ECR):
docker tag meu-springboot-app:1.0 usuario/meu-springboot-app:1.0
docker push usuario/meu-springboot-app:1.0Um Dockerfile eficiente para aplicações Java deve equilibrar performance, tamanho da imagem e facilidade de manutenção. A ideia é evitar imagens pesadas, reduzir tempo de build e garantir que a aplicação rode de forma consistente em qualquer ambiente.
- FROM
Define a imagem base. Exemplo:
FROM ubuntu:22.04- LABEL
Adiciona metadados à imagem, como autor ou versão.
LABEL maintainer="[email protected]"- RUN
Executa comandos durante a construção da imagem.
RUN apt-get update && apt-get install -y python3- COPY / ADD
Copia arquivos do host para dentro da imagem.
COPY app.py /usr/src/app/- WORKDIR
Define o diretório de trabalho dentro da imagem.
WORKDIR /usr/src/app- ENV
Define variáveis de ambiente.
ENV PORT=5000- EXPOSE
Indica a porta que o container vai usar.
EXPOSE 5000- CMD
Define o comando padrão que será executado quando o container iniciar.
CMD ["python3", "app.py"]- ENTRYPOINT
Similar ao CMD, mas fixa o comando principal, permitindo argumentos adicionais.
ENTRYPOINT ["python3", "app.py"]-
Usar imagens oficiais e leves (como openjdk:17-jdk-slim ou eclipse-temurin).
-
Multi-stage builds para separar o processo de compilação da execução.
-
Evitar copiar arquivos desnecessários (usar .dockerignore).
-
Definir variáveis de ambiente para configuração.
-
Expor apenas as portas necessárias.
# Imagem base leve
FROM openjdk:17-jdk-slim
# Diretório de trabalho
WORKDIR /app
# Copiar o JAR da aplicação
COPY target/minha-app.jar app.jar
# Expor porta padrão
EXPOSE 8080
# Comando de inicialização
ENTRYPOINT ["java", "-jar", "app.jar"]Esse exemplo é simples, mas gera uma imagem maior porque o JAR já precisa estar pronto.
# Etapa 1: Build da aplicação
FROM maven:3.9.6-eclipse-temurin-17 AS build
WORKDIR /app
# Copiar código e dependências
COPY pom.xml .
COPY src ./src
# Compilar e empacotar
RUN mvn clean package -DskipTests
# Etapa 2: Imagem final
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Copiar apenas o JAR gerado
COPY --from=build /app/target/minha-app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]Vantagens:
A imagem final contém apenas o JRE e o JAR da aplicação.
O Maven e dependências de build não ficam na imagem final.
Redução significativa do tamanho da imagem.
Crie um arquivo .dockerignore para evitar copiar arquivos desnecessários:
target/
.git
README.md
*.logIsso mantém a imagem mais limpa e rápida de construir.
- Heap size configurável:
ENV JAVA_OPTS="-Xms512m -Xmx1024m"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]-
Camadas otimizadas: copie primeiro arquivos que mudam menos (como pom.xml) para aproveitar cache de build.
-
Imagens base Alpine: reduzem tamanho, mas podem exigir ajustes em bibliotecas nativas.
Aplicações web Spring Boot → multi-stage build com Maven.
Microserviços leves → imagens base alpine para reduzir footprint.
Ambientes corporativos → uso de registries privados e tags versionadas (1.0.0, prod, dev).
O docker-compose facilita a orquestração de múltiplos containers, permitindo definir serviços (como aplicação e banco de dados) em um único arquivo YAML. Isso é especialmente útil para rodar aplicações que dependem de bancos como MySQL ou PostgreSQL.
Ferramenta para definir e gerenciar ambientes multi-container.
Usa um arquivo docker-compose.yml para descrever serviços, redes e volumes.
Permite subir todo o ambiente com um único comando:
docker-compose up -dversion: '3.8'
services:
app:
image: openjdk:17-jdk-slim
container_name: minha-app
working_dir: /app
volumes:
- ./target:/app
command: ["java", "-jar", "meu-app.jar"]
ports:
- "8080:8080"
depends_on:
- postgres
postgres:
image: postgres:15
container_name: meu-postgres
environment:
POSTGRES_USER: usuario
POSTGRES_PASSWORD: senha
POSTGRES_DB: minha_base
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:O que acontece aqui:
O serviço postgres cria automaticamente o banco minha_base.
Usuário e senha são configurados via variáveis de ambiente.
Os dados ficam persistidos no volume postgres_data.
Subir os serviços:
docker-compose up -dParar os serviços:
docker-compose downVer logs de um serviço específico:
docker-compose logs -f app-
Usar volumes para persistência de dados.
-
Definir variáveis sensíveis em arquivos .env (não direto no YAML).
-
Versionar o docker-compose.yml junto ao código da aplicação.
-
Usar depends_on para garantir ordem de inicialização.
Em aplicações modernas, especialmente com Spring Boot, é fundamental separar configurações de acordo com o ambiente (desenvolvimento, testes, produção). Isso garante flexibilidade, segurança e facilidade de manutenção.
São valores externos que podem ser usados pela aplicação sem precisar alterar o código.
Permitem configurar credenciais, URLs de banco de dados, portas, entre outros.
Evitam expor informações sensíveis em arquivos versionados.
Exemplo de uso no Docker:
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/minha_base
SPRING_DATASOURCE_USERNAME: usuario
SPRING_DATASOURCE_PASSWORD: senhaO Spring Boot permite definir perfis (dev, test, prod) para carregar configurações específicas.
-
Arquivo padrão: application.yml ou application.properties.
-
Perfis: application-dev.yml, application-prod.yml.
Exemplo application.yml (arquivo base):
spring:
profiles:
active: devExemplo application-dev.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: dev_user
password: dev_pass
jpa:
hibernate:
ddl-auto: updateExemplo application-prod.yml:
spring:
datasource:
url: jdbc:postgresql://postgres:5432/prod_db
username: prod_user
password: prod_pass
jpa:
hibernate:
ddl-auto: none- Via variável de ambiente:
export SPRING_PROFILES_ACTIVE=prod- Via linha de comando:
java -jar minha-app.jar --spring.profiles.active=prod- Via docker-compose:
environment:
SPRING_PROFILES_ACTIVE: prod-
Nunca versionar credenciais sensíveis → use variáveis de ambiente ou serviços de segredos (Vault, AWS Secrets Manager).
-
Separar ambientes claramente → cada perfil deve ter seu próprio arquivo.
-
Automatizar seleção de perfil → pipelines de CI/CD podem definir o perfil correto.
-
Manter consistência → nomes de variáveis e perfis devem seguir padrão (dev, staging, prod).
Rodar aplicações Java dentro de containers é ótimo para padronizar ambientes, mas quando chega a hora de testar e depurar (debug), precisamos de estratégias específicas para não perder visibilidade do que acontece dentro do container.
-
Testes unitários e de integração:
-
Devem ser executados antes de empacotar a aplicação no container (via Maven/Gradle).
-
Exemplo:
-
mvn test-
Testes de integração com banco de dados:
- Use docker-compose para subir aplicação + banco e rodar testes contra esse ambiente.
-
Testcontainers:
-
Biblioteca Java que cria containers temporários para testes automatizados.
-
Exemplo: subir um PostgreSQL em container apenas durante os testes.
-
1. Logs
Capturar logs da aplicação:
docker logs -f meu-containerRedirecionar logs para arquivos montados em volumes, facilitando análise.
2. Acesso ao container
Entrar no container para inspecionar arquivos ou processos:
docker exec -it meu-container bash3. Debug remoto (JDWP)
Para depurar código Java rodando dentro de um container, habilite o Java Debug Wire Protocol (JDWP):
No Dockerfile:
ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"]No docker-compose.yml:
ports:
- "8080:8080"
- "5005:5005"O Testcontainers é uma biblioteca Java que permite criar e gerenciar containers Docker diretamente nos testes automatizados. Ele é amplamente usado em projetos Spring Boot e Java para rodar testes de integração com bancos de dados, mensageria e outros serviços sem precisar configurar manualmente o ambiente.
Biblioteca que cria containers temporários durante a execução dos testes.
Permite rodar serviços reais (MySQL, PostgreSQL, Kafka, Redis, etc.) sem depender de instalações locais.
Containers são iniciados e destruídos automaticamente, garantindo isolamento e repetibilidade.
Maven:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.20.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.20.0</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation 'org.testcontainers:testcontainers:1.20.0'
testImplementation 'org.testcontainers:postgresql:1.20.0'import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.testcontainers.containers.PostgreSQLContainer;
@SpringBootTest
class MeuTeste {
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("usuario")
.withPassword("senha");
static {
postgres.start();
System.setProperty("spring.datasource.url", postgres.getJdbcUrl());
System.setProperty("spring.datasource.username", postgres.getUsername());
System.setProperty("spring.datasource.password", postgres.getPassword());
}
@Test
void contextoCarregado() {
// Aqui você pode rodar testes que usam o banco real em container
}
}