Docker y Kotlin: contenerización de aplicaciones para desarrolladores

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: por qué Docker y Kotlin son la pareja ideal

El desarrollo moderno es impensable sin la contenerización. Docker se ha convertido en el estándar de facto para empaquetar, distribuir y ejecutar aplicaciones. Kotlin, por su parte, está ganando popularidad rápidamente gracias a su sintaxis concisa, compatibilidad total con Java y soporte multiplataforma. La combinación de Docker y Kotlin permite crear entornos ligeros, escalables y predecibles, desde una simple aplicación de servidor en JVM hasta un binario nativo para IoT.

En este artículo, analizaremos cómo contenerizar correctamente proyectos Kotlin, optimizar el tamaño de las imágenes y evitar errores típicos. Todos los ejemplos de código se pueden adaptar a su proyecto.



1. Contenerización básica de una aplicación Kotlin/JVM

Empecemos con el escenario clásico: una aplicación Kotlin que se ejecuta en JVM. Para la compilación usaremos Gradle, la herramienta estándar para proyectos Kotlin.



1.1. Estructura del proyecto

Supongamos que tenemos un servidor HTTP simple en Ktor. La estructura del proyecto:

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


1.2. Dockerfile para compilación multi-etapa

La práctica clave es la compilación multi-etapa (multi-stage build). La primera etapa compila el fat JAR con Gradle, la segunda utiliza una imagen JRE mínima para la ejecución.

# Etapa 1: compilaciónFROM gradle:8.5-jdk21 AS buildWORKDIR /appCOPY --chown=gradle:gradle . .RUN gradle build --no-daemon -x test

# Etapa 2: ejecuciónFROM eclipse-temurin:21-jre-alpineWORKDIR /appCOPY --from=build /app/build/libs/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]


1.3. Optimización: almacenamiento en caché de dependencias

Para no recompilar las dependencias con cada cambio de código, divida el COPY en dos partes:

FROM gradle:8.5-jdk21 AS buildWORKDIR /app# Primero copiamos solo los archivos de compilaciónCOPY build.gradle.kts settings.gradle.kts ./COPY gradle/ gradle/RUN gradle dependencies --no-daemon# Luego copiamos los fuentesCOPY src/ src/RUN gradle build --no-daemon -x test

Este truco utiliza el mecanismo de almacenamiento en caché de capas de Docker: la imagen se reconstruye solo cuando cambia build.gradle.kts, no con cada modificación del código.



2. Contenerización de aplicaciones Kotlin/Native

Kotlin/Native permite compilar código en binarios nativos sin JVM. Esto es ideal para microservicios que necesitan un tamaño de imagen mínimo y un inicio rápido.



2.1. Dockerfile para Native

Para compilar un binario nativo, usamos una imagen con el compilador Kotlin/Native. La imagen final es scratch (vacía) o distroless.

# Etapa de compilaciónFROM jetbrains/kotlin-native:2.0.0 AS buildWORKDIR /appCOPY . .RUN kotlinc-native src/main/kotlin/Main.kt -o app

# Etapa de ejecución: imagen mínimaFROM alpine:3.19WORKDIR /appCOPY --from=build /app/app.kexe appEXPOSE 8080CMD ["./app"]

Importante: Para Alpine puede ser necesario instalar libc6-compat si el binario se compiló con glibc. Use FROM busybox:glibc para un tamaño aún menor.



2.2. Comparación de tamaños de imágenes

  • 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 microservicios de alta carga, el enfoque Native proporciona un ahorro significativo de recursos.



3. Docker Compose y proyectos multimódulo

Las aplicaciones Kotlin complejas a menudo constan de varios módulos: API, base de datos, caché. Docker Compose simplifica la orquestación.



3.1. Ejemplo de docker-compose.

Blogs

Book Recommendations