Docker e Java: conteinerização avançada de aplicações

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Docker e Java: conteinerização avançada de aplicações



A conteinerização de aplicações Java com Docker tornou-se há muito tempo um padrão da indústria. No entanto, Dockerfiles básicos e comandos simples como docker run são apenas a ponta do iceberg. Em um nível avançado, os desenvolvedores enfrentam desafios como otimização do tamanho das imagens, ajuste fino da JVM dentro do contêiner, organização de builds multi-estágio e orquestração de microsserviços. Neste artigo, abordaremos as principais técnicas que o ajudarão a elevar a conteinerização Java a um nível profissional.



1. Builds multi-estágio: imagem mínima para produção



Um dos principais problemas na conteinerização Java é o tamanho da imagem final. A imagem base openjdk:17-jdk pesa cerca de 400 MB, o que é excessivo para o runtime. A solução é o build multi-estágio (multi-stage build).



O primeiro estágio (build) usa o JDK completo e ferramentas de build (Maven/Gradle). O segundo estágio (runtime) usa uma imagem JRE leve e copia apenas o JAR/WAR compilado.



# Estágio 1: Compilação da aplicaçãoFROM maven:3.8.5-openjdk-17 AS builderWORKDIR /appCOPY pom.xml .COPY src ./srcRUN mvn clean package -DskipTests

# Estágio 2: Imagem mínima de runtimeFROM openjdk:17-jre-slimWORKDIR /app# Copia apenas o artefato compiladoCOPY --from=builder /app/target/myapp-*.jar app.jarEXPOSE 8080CMD ["java", "-jar", "app.jar"]


Vantagens:

  • A imagem final pesa ~180 MB em vez de 400+ MB
  • Reduz a superfície de ataque (sem compilador, utilitários desnecessários)
  • Acelera o tempo de deploy e download das imagens


2. Configuração da JVM para funcionar em contêiner



Por muito tempo, a JVM se adaptou mal às limitações dos contêineres (cgroups). A partir do Java 10, surgiram flags para especificar explicitamente os recursos, e no Java 17+ o comportamento tornou-se mais previsível. No entanto, em um nível avançado, é importante controlar a memória e a CPU manualmente.



Parâmetros JVM essenciais para contêiner:

  • -XX:MaxRAMPercentage=75.0 — aloca 75% da memória do contêiner para o heap (em vez do -Xmx fixo)
  • -XX:+UseContainerSupport — ativa a percepção das limitações do contêiner (ativado por padrão desde o Java 10+)
  • -XX:ActiveProcessorCount=2 — especifica explicitamente o número de processadores disponíveis
  • -XX:+ExitOnOutOfMemoryError — encerra o processo abruptamente em caso de OutOfMemoryError (para reinicialização rápida do contêiner)


# Exemplo de Dockerfile com flags JVM otimizadasFROM eclipse-temurin:17-jre-alpineWORKDIR /appCOPY target/app.jar app.jar

# Configuração da JVM para o contêinerENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0 \ -XX:+UseContainerSupport \ -XX:+ExitOnOutOfMemoryError \ -XX:+PrintGCDetails"

EXPOSE 8080CMD ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]


Importante: Use eclipse-temurin ou amazon-corretto — são imagens oficiais, bem mantidas e com política transparente de atualizações.



3. Docker Compose para arquitetura de microsserviços



Em projetos reais, uma aplicação Java raramente existe isoladamente. Geralmente é uma combinação: backend Spring Boot + PostgreSQL + Redis + Kafka. O Docker Compose permite descrever toda a infraestrutura em um único arquivo YAML.



version: '3.8'

services: postgres: image: postgres:15-alpine environment: POSTGRES_DB: myapp POSTGRES_USER: user POSTGRES_PASSWORD: secret volumes: - pgdata:/var/lib/postgresql/data networks: - backend

redis: image: redis:7-alpine ports: - "6379:6379" networks: - backend

app: build: context: . dockerfile: Dockerfile ports: - "8080:8080" environment: SPRING_DATASOURCE_URL: jdbc:postgresql:

Blogs

Book Recommendations