Despliegue de Kotlin en Kubernetes: guía básica en la práctica
Kubernetes (K8s) se ha convertido en el estándar para la orquestación de aplicaciones contenerizadas. Si desarrollas aplicaciones de servidor en Kotlin (usando Ktor, Spring Boot o http4k), tarde o temprano surgirá la cuestión de su despliegue en un clúster. En esta guía, recorreremos el camino desde el empaquetado de una aplicación Kotlin en una imagen Docker hasta su ejecución en Kubernetes utilizando ConfigMap e Ingress. Todos los ejemplos son funcionales y están listos para adaptarse.
1. Preparación de la aplicación Kotlin y la imagen Docker
Como ejemplo, tomaremos una aplicación simple en Ktor (se puede reemplazar por cualquier otro framework). Nuestra aplicación escuchará en el puerto 8080 y devolverá un JSON con la versión.
// src/main/kotlin/com/example/Application.ktimport io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.routing.*import io.ktor.server.response.*
fun main() { embeddedServer(Netty, port = 8080) { routing { get("/") { call.respond(mapOf("app" to "kotlin-on-k8s", "version" to "1.0.0")) } } }.start(wait = true)}Compilaremos la aplicación en un fat JAR usando Gradle (plugin shadow). Después de la compilación, crearemos un Dockerfile:
# DockerfileFROM openjdk:17-jdk-slimWORKDIR /appCOPY build/libs/app-all.jar app.jarEXPOSE 8080CMD ["java", "-jar", "app.jar"]Construimos la imagen y la subimos a un registro (por ejemplo, Docker Hub):
docker build -t youruser/kotlin-app:1.0.0 .docker push youruser/kotlin-app:1.0.02. Creación de manifiestos de Kubernetes
Ahora describiremos los recursos para el despliegue. Crearemos tres archivos: deployment.yaml, service.yaml y configmap.yaml.
2.1. ConfigMap para la configuración
Extraeremos la configuración de la aplicación (por ejemplo, el nivel de registro o la cadena de conexión) en un ConfigMap:
# configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: app-configdata: LOG_LEVEL: "DEBUG" APP_MODE: "production"2.2. Deployment
En el manifiesto Deployment especificaremos la imagen, el puerto, las réplicas y pasaremos las variables del ConfigMap:
# deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: kotlin-appspec: replicas: 2 selector: matchLabels: app: kotlin-app template: metadata: labels: app: kotlin-app spec: containers: - name: app image: youruser/kotlin-app:1.0.0 ports: - containerPort: 8080 envFrom: - configMapRef: name: app-config livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 10 periodSeconds: 52.3. Service
El Service balanceará el tráfico entre los pods:
# service.yamlapiVersion: v1kind: Servicemetadata: name: kotlin-app-servicespec: selector: app: kotlin-app ports: - protocol: TCP port: 80 targetPort: 8080 type: ClusterIP3. Despliegue en el clúster y configuración de Ingress
Aplicaremos los manifiestos:
kubectl apply -f configmap.yamlkubectl apply -f deployment.yamlkubectl apply -f service.yamlVerificaremos que los pods estén en ejecución:
kubectl get podskubectl logs <pod-name>Ahora haremos que la aplicación sea accesible desde el exterior. Crearemos un Ingress (se asume que en el clúster está instalado un Ingress Controller, por ejemplo, NGINX):
# ingress.yamlapiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: kotlin-app-ingressspec: rules: - host: kotlin.example.com http: paths: