Ir al contenido

De Eureka a Consul: Migrando el Service Discovery en Spring Cloud

·1079 palabras·6 mins
Michael Antonio Tomaylla
Autor
Michael Antonio Tomaylla
De la complejidad técnica a la simplicidad que genera valor

Introducción — Cómo dejar atrás las direcciones impresas
#

Seamos claros: hardcodear IPs en microservicios es como usar un mapa de papel en plena era GPS. Durante años, Netflix Eureka fue la opción natural en proyectos Spring Cloud: fácil de integrar, confiable y conocida. Pero con el tiempo necesitábamos más: eficiencia, funciones avanzadas y un roadmap activo.

En esta guía cuento la migración real que realicé de Eureka a HashiCorp Consul: por qué decidí dar el salto, los pasos prácticos que seguí, los problemas que enfrenté y los beneficios medidos en producción. Todo con ejemplos claros y recomendaciones aplicables.

Migración de Eureka a Consul — ilustración de servicios

Qué es Service Discovery (sin vueltas)
#

Service Discovery es el GPS de los microservicios: permite que un servicio localice dinámicamente IP y puerto de otro. Evita configuraciones estáticas, facilita el escalado automático y mejora la resiliencia.

Patrones comunes:

  • Client-side discovery: el cliente consulta el registry (Eureka/Consul) y selecciona una instancia.
  • Server-side discovery: un proxy o router (Kubernetes Service, load balancer) resuelve por ti.

Si aún confías en IPs fijas, tu código necesita una conversación urgente… y un café.

Por qué Eureka fue estándar — icono de Spring Cloud y facilidad

Por qué Eureka fue el estándar (y por qué lo quisimos)
#

Eureka ganó tracción porque integrar con Spring Cloud era sencillo: unas dependencias, unas anotaciones y las apps se registraban solas. Sus ventajas históricas:

  • Setup rápido gracias a autoconfiguración.
  • Filosofía AP: alta disponibilidad tolerando registros obsoletos.
  • Integración natural con la pila Spring Cloud.

Con todo, empecé a ver limitaciones que pesaban más que la comodidad.

Limitaciones que me empujaron a migrar
#

1) Desarrollo estancado

Eureka quedó en mantenimiento. Construir sobre un proyecto sin roadmap suma deuda técnica.

2) Consumo de recursos

Eureka Server es una JVM completa: medimos ~300–500 MB RAM por nodo. En clusters grandes eso suma.

3) Funcionalidad limitada

Eureka hace discovery, pero no KV store, health checks avanzados ni mesh integrado.

Si tu objetivo es una plataforma moderna, depender únicamente de Eureka hoy es como llevar una navaja suiza sin hoja.

Por qué Consul — icono de HashiCorp y funcionalidades

Por qué HashiCorp Consul (no es solo discovery)
#

Consul es una plataforma de networking y configuración distribuida con ventajas claras:

  • Service Discovery robusto.
  • Health checks avanzados (HTTP, TCP, scripts, gRPC).
  • Key-Value store para configuración distribuida.
  • Service Mesh con Consul Connect (mTLS y enrutamiento).
  • Soporte multi-datacenter nativo.
  • Implementación ligera (escrito en Go).

En la práctica: menos componentes, más funciones y un proyecto con roadmap activo.

Comparativa breve
#

  • Lenguaje: Eureka = Java, Consul = Go.
  • Consumo RAM por nodo: Eureka ≈ 300–500 MB, Consul ≈ 40–80 MB.
  • Desarrollo: Eureka en mantenimiento, Consul en desarrollo activo.
  • KV Store: Eureka ❌, Consul ✅.
  • Service Mesh: Eureka ❌, Consul ✅ (Consul Connect).
  • Health checks: Eureka básico, Consul avanzado.
  • UI: Eureka simple, Consul más moderna y usable.

Plan de migración práctico — icono de pasos

Plan de migración: enfoque práctico
#

La mayor parte del esfuerzo fue de configuración; el código de la app casi no cambió. Resumen en 4 pasos:

  1. Actualizar dependencias (pom.xml)
  2. Ajustar configuración (bootstrap.yml / application-*.yml)
  3. Verificar/ajustar código (mínimos cambios)
  4. Orquestar con Docker Compose / CI / Kubernetes

Paso 1 — Dependencias (pom.xml)
#

<!-- FUERA -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<!-- DENTRO -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

Nota: spring-cloud-starter-bootstrap permite contactar a Consul durante la fase de bootstrap. Es básico y no conviene obviarlo.

Paso 2 — Configuración: bootstrap.yml y application-docker.yml
#

Mantén bootstrap.yml minimalista: lo esencial para localizar Consul.

bootstrap.yml
spring:
  application:
    name: ms-customer
  cloud:
    consul:
      host: consul
      port: 8500

En el profile de Docker (application-docker.yml) defines registro y health checks:

application-docker.yml
spring:
  cloud:
    consul:
      discovery:
        service-name: ${spring.application.name}
        instance-id: ${spring.application.name}:${server.port}
        prefer-ip-address: true
        health-check-path: /actuator/health/liveness
        health-check-interval: 10s

management:
  endpoint:
    health:
      probes:
        enabled: true

Puntos clave:

  • prefer-ip-address: true es crítico en Docker para evitar localhost.
  • Usa Actuator para health checks reales.
  • Mantén bootstrap.yml simple; mueve el resto a application-*.yml para evitar conflictos en bootstrap.

Paso 3 — Código Java: casi sin drama
#

Las abstracciones de Spring Cloud (RestTemplate @LoadBalanced, FeignClient, etc.) mayormente no requieren cambios. Ejemplo típico:

@SpringBootApplication
public class CustomerApplication {
  // ... mismo código
}

@FeignClient(name = "ms-activity")
public interface ActivityClient { ... }

Nota: @EnableDiscoveryClient es opcional en Spring Boot 3.x; Spring Cloud lo auto-configura.

Paso 4 — Orquestación: Docker Compose mínimo
#

Ejemplo mínimo para pruebas locales:

services:
  consul:
    image: hashicorp/consul:latest
    ports: ["8500:8500"]
    command: agent -server -ui -bootstrap-expect=1 -client=0.0.0.0

  ms-customer:
    build: .
    environment:
      - SPRING_PROFILES_ACTIVE=docker
    depends_on:
      - consul

Consejos:

  • depends_on ayuda en Compose; en Kubernetes usa readiness probes.
  • En producción, configura probes, políticas de red y seguridad.

Depuración y problemas comunes — lupa y consola

Problemas comunes y soluciones prácticas
#

1) Servicio no aparece en Consul

  • Causa: bootstrap.yml complejo o conflictivo.
  • Solución: simplifica bootstrap.yml y mueve propiedades runtime a application-*.yml.

2) Se registra con localhost o IP incorrecta

  • Causa: registro con localhost en Docker.
  • Solución: prefer-ip-address: true y revisar la configuración de red Docker.

3) Health check falla y servicio se desregistra

  • Causa: path incorrecto o conectividad entre contenedores.
  • Solución: valida el endpoint desde el contenedor de Consul (curl o comandos de Consul) y corrige el path/puerto.

Depuración: entra al contenedor de Consul, revisa el catálogo y el estado de health. Muchas veces es un path mal escrito o un puerto distinto.

Resultados: métricas y beneficios observados
#

Consumo de memoria

  • Eureka: ~400 MB por nodo
  • Consul: ~60 MB por nodo
  • Ahorro aproximado: ~85% en memoria del servicio de discovery

Tiempo de detección de caídas

  • Eureka: ~90 segundos
  • Consul: ~20 segundos
  • Detección ~4.5x más rápida, con recuperación más veloz y menor impacto al usuario

Beneficios cualitativos:

  • UI más amigable para debugging.
  • KV store integrado, menos piezas en el stack.
  • Camino a service mesh con Consul Connect (mTLS y políticas).
  • Menor coste operativo por menos RAM y procesos más ligeros.

Roadmap: Vault, Connect y optimización

Roadmap y próximos pasos
#

  1. Seguridad y gestión de secretos
    • Implementar ACLs en Consul.
    • Integrar HashiCorp Vault para secretos.
  2. Service Mesh
    • Activar Consul Connect para mTLS automático y control de políticas entre servicios.
  3. Optimización de runtime
    • Evaluar compilación nativa (GraalVM) para reducir memoria y acelerar arranques.

Integrar Vault y Consul Connect abre muchas posibilidades, pero requiere diseño de seguridad y revisiones.

Conclusión — ¿vale la pena migrar?
#

Para mí fue una inversión estratégica: modernizó la plataforma, redujo costes y preparó el camino para service mesh y gestión centralizada de configuración y secretos. La mayor parte del esfuerzo fue de configuración; el código de las aplicaciones prácticamente permaneció igual. Resultado: migración alcanzable para la mayoría de equipos con buenas prácticas.

¿Quieres que arme el repositorio de ejemplo y un checklist paso a paso? Dime si prefieres Docker Compose para pruebas locales o manifiestos Kubernetes para staging/producción. ¡Hablemos de microservicios sin mapas de papel!