Docker e Kotlin: conteinerização de aplicações do A ao Z
A conteinerização tornou-se o padrão de facto para o desenvolvimento moderno. Ela resolve o problema "funciona na minha máquina" e simplifica o CI/CD. Neste artigo, vamos explorar como conteinerizar eficientemente aplicações Kotlin com Docker — desde a criação de um Dockerfile simples até otimizações de produção e orquestração.
1. Fundamentos: Dockerfile para aplicação Kotlin
O coração da conteinerização é o Dockerfile. Para aplicações Kotlin, que compilam para bytecode JVM, usamos a construção em múltiplos estágios (multi-stage build). Isso permite separar o ambiente de construção do ambiente de execução, reduzindo o tamanho da imagem final.
Vamos considerar uma aplicação típica em Kotlin usando Gradle (arquivo build.gradle.kts simplificado):
// build.gradle.ktsplugins { kotlin("jvm") version "1.9.0" application id("com.google.cloud.tools.jib") version "3.4.0" // opcional}
application { mainClass.set("com.example.MainKt")}Criaremos um Dockerfile com dois estágios:
# Estágio 1: ConstruçãoFROM gradle:8.5-jdk21 AS builderWORKDIR /appCOPY build.gradle.kts settings.gradle.kts ./COPY gradle ./gradleCOPY src ./srcRUN gradle build --no-daemon
# Estágio 2: ExecuçãoFROM eclipse-temurin:21-jre-alpineWORKDIR /appCOPY --from=builder /app/build/libs/my-app-*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]Comandos para construir e executar:
docker build -t my-kotlin-app .docker run -p 8080:8080 my-kotlin-appRecomendações:
- Use
eclipse-temurin(OpenJDK) em vez do JDK completo — a imagem é menor. - Cacheie as dependências: primeiro copie
build.gradle.kts, depoissrc. - Para aplicações Spring Boot, você pode usar
layerspara construção incremental.
2. Otimização com Jib e Gradle
Escrever um Dockerfile manualmente é o clássico, mas existem ferramentas que automatizam o processo. O Jib (do Google) integra-se com Maven/Gradle e constrói imagens Docker otimizadas sem a necessidade do daemon Docker.
Adicione o plugin Jib no build.gradle.kts:
plugins { id("com.google.cloud.tools.jib") version "3.4.0"}
jib { from { image = "eclipse-temurin:21-jre-alpine" } to { image = "my-registry/my-kotlin-app:latest" } container { ports = listOf("8080") jvmFlags = listOf("-Xms512m", "-Xmx1024m") }}Construção com um único comando:
./gradlew jibDockerBuildVantagens do Jib:
- Divisão automática em camadas (dependências, recursos, classes).
- Não requer Dockerfile.
- Funciona sem o daemon Docker — ideal para CI/CD.
Exemplo de aplicação Kotlin (servidor HTTP simples):
// src/main/kotlin/com/example/Main.ktpackage com.example
import com.sun.net.httpserver.HttpServerimport java.net.InetSocketAddress
fun main() { val server = HttpServer.create(InetSocketAddress(8080), 0) server.createContext("/") { exchange -> val response = "Hello from Kotlin in Docker!" exchange.sendResponseHeaders(200, response.length.toLong()) exchange.responseBody.write(response.toByteArray()) exchange.close() } server.start() println("Server started on port 8080")}3. Docker Compose: aplicações multicontêiner
Projetos reais raramente consistem em um único serviço. O Docker Compose permite descrever e executar vários contêineres (por exemplo, aplicação + banco de dados + Redis).
Criaremos um docker-compose.yml para uma aplicação Kotlin com PostgreSQL:<