Docker e Kotlin: conteinerização de aplicações de nível avançado

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
```html

Docker e Kotlin: conteinerização de aplicações de nível avançado



A conteinerização tornou-se uma parte essencial do desenvolvimento moderno. Se você já domina os princípios básicos do Docker e escreveu algumas imagens simples em Kotlin, é hora de passar para o próximo nível. Neste artigo, abordaremos técnicas avançadas: builds multi-estágio, otimização do tamanho da imagem final, trabalho com frameworks populares (Ktor, Spring Boot) e gerenciamento eficiente de corrotinas em ambiente conteinerizado.



1. Builds multi-estágio (Multi-stage builds)



Um dos principais problemas ao conteinerizar aplicações JVM é o tamanho da imagem. Uma imagem base JDK pode pesar centenas de megabytes. O build multi-estágio permite separar as etapas de compilação e execução, deixando na imagem final apenas o JRE e o JAR compilado.



Vamos considerar um exemplo para uma aplicação Kotlin compilada com Gradle:



# Estágio de buildFROM gradle:7.6-jdk17 AS builderWORKDIR /appCOPY build.gradle.kts settings.gradle.kts ./COPY src ./srcRUN gradle build --no-daemon -x test

# Estágio de execuçãoFROM eclipse-temurin:17-jre-alpineWORKDIR /appCOPY --from=builder /app/build/libs/*.jar app.jarEXPOSE 8080CMD ["java", "-jar", "app.jar"]


Por que isso é eficiente?

  • No estágio de build, usamos o JDK completo e o Gradle, mas eles não entram na imagem final.
  • A imagem final contém apenas o JRE (Java Runtime Environment), reduzindo o tamanho em 3 a 5 vezes.
  • O Alpine Linux reduz ainda mais o volume para ~150-200 MB, em vez de 600+ MB.


2. Otimização de camadas e cache



O Docker armazena em cache as camadas, mas apenas se elas não forem alteradas. Para acelerar rebuilds, separe as dependências e o código fonte:



FROM gradle:7.6-jdk17 AS builderWORKDIR /app

# Primeiro, copie apenas os arquivos de dependênciasCOPY build.gradle.kts settings.gradle.kts ./RUN gradle dependencies --no-daemon

# Depois, o código fonte (muda com mais frequência)COPY src ./srcRUN gradle build --no-daemon -x test


Essa abordagem garante que a camada com dependências seja reconstruída apenas quando o arquivo build.gradle.kts for alterado. Caso contrário, o Docker usa o cache, economizando minutos a cada iteração.



Dica: para projetos Kotlin com muitas dependências (ex: Spring Boot), essa técnica é especialmente relevante — o carregamento do cache do Gradle pode levar de 2 a 3 minutos.



3. Conteinerização de aplicações Ktor



Ktor é um framework assíncrono leve em Kotlin, ideal para microsserviços. A conteinerização de uma aplicação Ktor requer configuração mínima, mas há nuances relacionadas às corrotinas.



Exemplo de Dockerfile para Ktor:



FROM gradle:7.6-jdk17 AS builderWORKDIR /appCOPY build.gradle.kts settings.gradle.kts ./RUN gradle dependencies --no-daemonCOPY src ./srcRUN gradle build --no-daemon -x test

FROM eclipse-temurin:17-jre-alpineWORKDIR /appCOPY --from=builder /app/build/libs/ktor-app-*.jar app.jarEXPOSE 8080

# Importante: configuração da JVM para corrotinasCMD ["java", "-XX:+UseZGC", "-Xms256m", "-Xmx512m", "-jar", "app.jar"]


Pontos-chave:

  • Use ZGC (Z Garbage Collector) — ele minimiza pausas, o que é crítico para aplicações assíncronas com muitas corrotinas.
  • Limite a memória com -Xms e -Xmx. Em contêineres, isso ajuda a evitar erros OOM.
  • Certifique-se de que o servidor Ktor não bloqueie a thread principal — as corrotinas devem ser configuradas via Dispatchers.IO ou um pool personalizado.


Exemplo de configuração do Ktor para funcionar em contêiner:



fun main() {    embeddedServer(Netty, port = 8080, host = "0.0.0.0") {        routing {            get("/") {```                

Blogs

Book Recommendations