Introdução ao Docker e Java
O desenvolvimento moderno de aplicações Java é impensável sem conteinerização. Docker é uma plataforma para empacotar, entregar e executar aplicações em ambientes isolados (contêineres). Para desenvolvedores Java, o Docker resolve o problema eterno: "Na minha máquina funciona!". O contêiner garante que sua aplicação seja executada da mesma forma na máquina local, no servidor de desenvolvimento e em produção.
Neste artigo, vamos analisar como conteinerizar aplicações Java com Docker: desde um Dockerfile simples até a otimização de imagens para arquitetura de microsserviços. Todos os exemplos são escritos em Java e prontos para uso.
Fundamentos do Docker para aplicações Java
O que é uma imagem Docker e um contêiner?
Uma imagem Docker é um modelo (somente leitura) que contém tudo o que é necessário para executar uma aplicação: JVM, bibliotecas, código e configurações. Um contêiner é uma instância em execução da imagem. Para Java, isso significa que você não precisa instalar manualmente o JDK no servidor — a JVM já estará dentro do contêiner.
Criando um Dockerfile simples para Java
Vamos considerar um exemplo básico. Temos uma aplicação Java simples (por exemplo, HelloWorld.java).
// HelloWorld.javapublic class HelloWorld { public static void main(String[] args) { System.out.println("Hello from Docker and Java!"); }}Vamos criar um Dockerfile:
# Usamos a imagem oficial do OpenJDKFROM openjdk:11-jre-slim
# Definimos o diretório de trabalhoWORKDIR /app
# Copiamos o jar compilado ou arquivos .classCOPY HelloWorld.class .
# Comando de execuçãoCMD ["java", "HelloWorld"]Construção e execução:
# Construção da imagemdocker build -t hello-java .
# Execução do contêinerdocker run hello-javaSaída: Hello from Docker and Java!
Conteinerização de aplicações Spring Boot
Para projetos reais (por exemplo, com Spring Boot), o processo se torna mais complexo. Vamos considerar um microsserviço típico.
Construção em múltiplos estágios (Multi-stage build)
Esta é a melhor prática para Java: primeiro compilamos a aplicação com o JDK completo, depois copiamos o resultado para uma imagem leve com JRE.
# Estágio 1: CompilaçãoFROM maven:3.8.5-openjdk-11 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn clean package -DskipTests
# Estágio 2: ExecuçãoFROM openjdk:11-jre-slimWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]Explicação:
- build — usa Maven e o JDK completo para compilação.
- Imagem final — contém apenas JRE e o arquivo jar pronto. O tamanho da imagem é reduzido em 2-3 vezes.
Otimização do cache de camadas
O Docker armazena em cache cada camada (instrução). Para acelerar a construção, coloque as dependências que raramente mudam no início:
FROM maven:3.8.5-openjdk-11 AS buildWORKDIR /app# Armazenamos dependências em cacheCOPY pom.xml .RUN mvn dependency:go-offline# Agora copiamos o códigoCOPY src ./srcRUN mvn clean packageAgora, se você alterar apenas o código, o Docker reconstruirá apenas as últimas camadas, enquanto as dependências serão obtidas do cache.
Trabalhando com variáveis de ambiente e perfis
Passando parâmetros para a aplicação Java
O Docker permite configurar a aplicação de forma flexível através de variáveis de ambiente. Para o Spring Boot, isso é especialmente conveniente.
docker run -e SPRING_PROFILES_ACTIVE=prod -e DB_URL=jdbc:postgresql://db:5432/mydb my-appNo Dockerfile, você pode definir valores padrão:
ENV SPRING_PROFILES_ACTIVE=devENV DB_URL=jdbc:h2:mem:testdbExemplo de docker-compose para Java + BD
Para microsserviços, é conveniente usar docker-compose.yml:
version: '3.8'services: app: bu