Docker e Kotlin: conteinerização de aplicações para desenvolvedores

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

Introdução: por que Docker e Kotlin são a combinação perfeita

O desenvolvimento moderno é impensável sem conteinerização. Docker se tornou o padrão de facto para empacotar, distribuir e executar aplicações. Kotlin, por sua vez, está ganhando popularidade rapidamente devido à sua sintaxe concisa, compatibilidade total com Java e suporte multiplataforma. A combinação de Docker e Kotlin permite criar ambientes leves, escaláveis e previsíveis — desde uma simples aplicação servidora na JVM até um binário nativo para IoT.

Neste artigo, vamos analisar como conteinerizar corretamente projetos Kotlin, otimizar o tamanho das imagens e evitar erros comuns. Todos os exemplos de código podem ser adaptados para o seu projeto.

1. Conteinerização básica de uma aplicação Kotlin/JVM

Vamos começar com o cenário clássico: uma aplicação Kotlin rodando na JVM. Para a construção, usaremos Gradle — a ferramenta padrão para projetos Kotlin.

1.1. Estrutura do projeto

Suponha que temos um servidor HTTP simples em Ktor. A estrutura do projeto:

my-kotlin-app/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    └── main/
        └── kotlin/
            └── com/
                └── example/
                    └── App.kt

1.2. Dockerfile para construção multi-estágio

A prática fundamental é a construção multi-estágio (multi-stage build). O primeiro estágio compila o fat JAR usando Gradle, o segundo usa uma imagem JRE mínima para execução.

# Estágio 1: compilação
FROM gradle:8.5-jdk21 AS build
WORKDIR /app
COPY --chown=gradle:gradle . .
RUN gradle build --no-daemon -x test

# Estágio 2: execução
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

1.3. Otimização: cache de dependências

Para não recompilar as dependências a cada alteração no código, divida o COPY em duas partes:

FROM gradle:8.5-jdk21 AS build
WORKDIR /app
# Primeiro, copie apenas os arquivos de compilação
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle/ gradle/
RUN gradle dependencies --no-daemon
# Depois, copie os fontes
COPY src/ src/
RUN gradle build --no-daemon -x test

Esse truque utiliza o mecanismo de cache de camadas do Docker: a imagem é reconstruída apenas quando build.gradle.kts é alterado, e não a cada modificação no código.

2. Conteinerização de aplicações Kotlin/Native

Kotlin/Native permite compilar código em binários nativos sem JVM. Isso é ideal para microsserviços que precisam de tamanho de imagem mínimo e inicialização rápida.

2.1. Dockerfile para Native

Para compilar o binário nativo, use uma imagem com o compilador Kotlin/Native. A imagem final é scratch (vazia) ou distroless.

# Estágio de compilação
FROM jetbrains/kotlin-native:2.0.0 AS build
WORKDIR /app
COPY . .
RUN kotlinc-native src/main/kotlin/Main.kt -o app

# Estágio de execução: imagem mínima
FROM alpine:3.19
WORKDIR /app
COPY --from=build /app/app.kexe app
EXPOSE 8080
CMD ["./app"]

Importante: Para Alpine, pode ser necessário instalar libc6-compat se o binário foi compilado com glibc. Use FROM busybox:glibc para um tamanho ainda menor.

2.2. Comparação de tamanhos de imagem

  • JVM (fat JAR + JRE): ~180-250 MB
  • JVM (distroless + slim JRE): ~80-120 MB
  • Native (Alpine): ~10-25 MB
  • Native (scratch): ~5-10 MB

Para microsserviços de alta carga, a abordagem Native oferece uma economia significativa de recursos.

3. Docker Compose e projetos multimódulo

Aplicações Kotlin complexas geralmente consistem em vários módulos: API, banco de dados, cache. O Docker Compose simplifica a orquestração.

3.1. Exemplo de docker-compose.

```

Blogs

Book Recommendations