Docker, Java e por que isso muda as regras do jogo
\n\nImagine: você escreveu uma aplicação Java incrível. Ela funciona no seu MacBook, mas quando você a entrega para um colega no Windows — tudo quebra. Familiar? E se o servidor for Linux? Nem precisa adivinhar — a clássica história "funciona na minha máquina".
\n\nA containerização com Docker resolve esse problema de uma vez por todas. Você empacota a aplicação junto com seu ambiente (JVM, bibliotecas, dependências) em um container leve que é executado da mesma forma em qualquer lugar. Para Java, isso é especialmente relevante — pois estamos acostumados com "Write Once, Run Anywhere", mas na prática esse idioma frequentemente falha devido a versões do JDK, bibliotecas do sistema ou configurações.
\n\nNeste artigo, vamos abordar a containerização de aplicações Java com Docker do início ao fim. Você aprenderá como escrever um Dockerfile, otimizar a imagem, usar Docker Compose e evitar as armadilhas comuns. Vamos lá!
\n\nO que é Docker e por que ele é útil para o desenvolvedor Java?
\n\nDocker é uma plataforma para empacotar, distribuir e executar aplicações em ambientes isolados — containers. Diferente das máquinas virtuais, os containers compartilham o kernel do SO, mas possuem seu próprio espaço de arquivos, rede e processos. Isso os torna leves (megabytes, não gigabytes) e rápidos (inicialização em segundos).
\n\nPara o desenvolvedor Java, o Docker oferece três superpoderes:
\n- \n
- Reprodutibilidade — chega de "funciona na minha máquina". Se o container foi executado localmente, ele será executado em qualquer servidor. \n
- Isolamento — cada aplicação vive em seu próprio mundo, sem interferir nas outras. Quer duas aplicações Java com versões diferentes do JDK? Fácil. \n
- Escalabilidade — containers são facilmente clonados, balanceados e orquestrados (Kubernetes, Docker Swarm). \n
Primeiro Dockerfile para uma aplicação Java
\n\nVamos começar com o básico. Temos uma aplicação Java padrão (por exemplo, Spring Boot ou apenas Main.java). Queremos empacotá-la em uma imagem Docker. A maneira mais simples é usar a imagem oficial do OpenJDK.
\n\nAqui está um Dockerfile mínimo:
# Usamos a imagem oficial do OpenJDK 17\nFROM openjdk:17-jdk-alpine\n\n# Definimos o diretório de trabalho\nWORKDIR /app\n\n# Copiamos o arquivo JAR para o container\nCOPY target/my-app.jar /app/my-app.jar\n\n# Executamos a aplicação\nCMD ["java", "-jar", "my-app.jar"]\n\nAgora, vamos construir a imagem e executar o container:
\n\n# Construção da imagem\ndocker build -t my-java-app .\n\n# Execução do container\ndocker run -p 8080:8080 my-java-app\n\nTudo funciona. Mas este é um exemplo ruim. Por quê? Vamos entender.
\n\nProblema nº1: Tamanho da imagem
\nA imagem openjdk:17-jdk-alpine pesa cerca de 150 MB. Isso é normal, mas se você adicionar todas as dependências, o tamanho pode crescer para mais de 500 MB. Para produção, isso é muito.
Problema nº2: Compilação e runtime na mesma imagem
\nCopiamos o JAR pronto, o que significa que a compilação (mvn clean package) precisa ser feita antecipadamente. É melhor usar uma construção em múltiplos estágios (multi-stage build) para separar a etapa de compilação da etapa de execução.
\n\nOtimização: construção em múltiplos estágios (multi-stage build)
\n\nA ideia é simples: no primeiro estágio, usamos uma imagem com Maven e JDK, compilamos o projeto e, no segundo, apenas o JRE e o JAR pronto. Isso reduz a imagem final drasticamente.
\n\n# Estágio de compilação\nFROM maven:3.8.5-openjdk-17 AS builder\nWORKDIR /build\nCOPY pom.xml .\nCOPY src ./src\nRUN mvn clean package -DskipTests\n\n# Estágio de execução\nFROM openjdk:17-jre-alpine\nWORKDIR /app\nCOPY --from=builder /build/target/my-app.jar /app/my-app.jar\nEXPOSE 8080\nCMD ["java", "-jar", "my-app.jar"]\n\nO que mudou?
\n- \n
- O primeiro estágio (
builder) contém Maven e JDK — necessário apenas para a compilação. \n - O segundo estágio usa uma imagem JRE leve (~50 MB \n