Skip to content

Cómo levantar un entorno de microservicios en local

This content is not available in your language yet.

Levantar un microservicio en local es fácil: lo dice su README. El problema empieza cuando el flujo que quieres probar pasa por cuatro, y cada uno llama a otros dos que no son tuyos.

Esta página no es un tutorial de una herramienta concreta: es qué piezas hacen falta, por qué la parte difícil no es la que parece, y cómo se resuelve cada una — con MicroLab al final, porque es lo que documenta este sitio, pero los cuatro problemas son los mismos uses lo que uses.

Un entorno local que sirva para algo necesita resolver cuatro cosas. En este orden de dificultad real, que casi nunca es el orden en que se abordan:

  1. Infraestructura común. Kafka, Redis, PostgreSQL, lo que use tu sistema. Es la parte más visible y la más resuelta: contenedores.
  2. Arranque de cada servicio. Su comando, su perfil, sus variables, su puerto. Es trabajo repetitivo pero mecánico.
  3. Comunicación entre servicios. A dónde llama cada uno. Aquí es donde se va la mañana, y es de lo que casi nadie habla.
  4. Datos. Un esquema creado y algo dentro con lo que probar.

Un docker-compose.yml con las piezas comunes y docker compose up. Es lo que hace todo el mundo y está bien: los contenedores son exactamente la herramienta adecuada para esto.

Dos detalles que muerden más tarde:

  • Los puertos colisionan. Cada equipo declara el 5432 y el 6379. En cuanto tienes dos proyectos abiertos, o levantas y bajas, empiezan los conflictos.
  • La infraestructura se comparte entre proyectos, pero los datos no. Reutilizar el mismo Postgres para dos sistemas distintos acaba en un esquema que nadie sabe de quién es.

Cada servicio tiene su forma: ./mvnw quarkus:dev, ./gradlew bootRun -Dspring.profiles.active=local, npm start, un binario. Con perfiles, variables y flags distintos.

Esto es lo que suele acabar escrito en un LOCAL_SETUP.md de cuarenta pasos: funciona, pero envejece mal. Nadie actualiza el documento cuando cambia un flag, y el siguiente que llega descubre el desfase a base de errores.

Un detalle que decide mucho más de lo que parece: no todos los servicios quieren correr igual. El que estás tocando lo quieres nativo, con recarga en caliente y con el depurador enganchado. Los otros tres solo tienen que estar levantados: en contenedor están bien, aislados y sin ensuciarte la máquina.

Aquí está el trabajo de verdad, y es el que ninguna herramienta de contenedores resuelve por ti.

Tu servicio bff llama a orders. En producción esa URL la da el descubrimiento de servicios o el ingress. En local, alguien tiene que decidir a dónde apunta, y las opciones no son equivalentes:

  • Al servicio levantado en tu máquina. Es lo que quieres cuando estás cambiando los dos lados. Pero entonces tienes que levantarlo también, con toda su cola de dependencias detrás.
  • Al entorno compartido de desarrollo. Te ahorra levantarlo, a cambio de VPN, de datos que cambian bajo tus pies y de que si ese entorno está caído, tú también.
  • A un mock. Perfecto cuando la respuesta de ese servicio te da igual, o cuando ni siquiera puedes llegar a él. A cambio de mantener el stub.

Lo caro no es elegir: es aplicar la elección. Cada opción significa cambiar una URL en la configuración de un repositorio que no es tuyo, acordarte de no commitearla, y deshacerlo cuando quieras probar otra cosa. Multiplica por servicios y por veces al día.

Y hay una trampa: la URL correcta depende de dónde corre quien llama. Un servicio nativo llega a un contenedor por localhost:puerto; un contenedor que llama a otro contenedor, por el nombre del servicio; y un contenedor que llama a algo nativo de tu máquina necesita el nombre especial del host. La misma dependencia, tres URLs distintas según cómo esté corriendo cada extremo.

Esquema creado, migraciones pasadas y unos datos mínimos. Suele resolverse con las migraciones de la propia aplicación más un script de semilla.

La regla que conviene no romper: el entorno local no toca bases de datos compartidas. Una migración lanzada sin querer contra el entorno de desarrollo común es una tarde perdida para todo el equipo.

EnfoqueBien paraDónde se queda corto
docker-compose de todoInfraestructura; un sistema pequeño y estableConstruir la imagen de tu servicio en cada cambio; sin recarga en caliente ni depurador cómodo; la comunicación sigue siendo configuración a mano
Scripts + LOCAL_SETUP.mdEmpezar rápidoEnvejece: nadie lo actualiza y falla distinto en cada máquina
TestcontainersTests de integración realesEl entorno nace y muere con el test; no es un sitio donde trabajar
Kubernetes local (Kind, minikube)Parecerse a producciónMucha máquina y mucho ciclo de build para el día a día; el bucle de cambio se alarga
Orquestador localEl bucle diario con varios serviciosHay que describir cada servicio una vez

Ninguno es tonto: resuelven cosas distintas y a menudo conviven. Lo que ninguno de los cuatro primeros hace es decidir por dependencia a dónde llama cada servicio y aplicarlo sin tocar los repositorios.

MicroLab es un orquestador de escritorio que se ocupa de las cuatro piezas, y trata la tercera como el problema principal que es.

  1. Describes cada servicio una vez. Apuntas a la carpeta del repositorio y se autodetecta su tecnología, sus puertos, la infraestructura que necesita y a quién llama. Revisas y ya está.
  2. Agrupas en un escenario los servicios de un flujo —«Checkout», «Alta de cliente»— y se levantan juntos, en orden y esperando a que cada uno esté sano.
  3. Por cada dependencia eliges local, nube o mock, y el motor reescribe la URL al arrancar inyectándola como configuración —flags -D o variables de entorno—, con la perspectiva correcta según dónde corra cada extremo. Tus repositorios no se tocan.
  4. La infraestructura común (Kafka, Redis, PostgreSQL) la gestiona la app en Docker, con auto-remapeo de puertos cuando colisionan.
  5. Cada servicio, nativo o en contenedor, a tu elección: nativo el que estás tocando, en contenedor los de fondo.

Y lo que montas se comparte: un escenario se exporta a un fichero autocontenido, así que quien entra nuevo clona, importa y arranca en vez de leerse el LOCAL_SETUP.md.