Módulo 5: Microservicio Orders — Scaffold, Docker & API Gateway
~1 hora
Objetivo
Crear el primer microservicio real (ms-orders) usando el Scaffold de Bancolombia, dockerizarlo, agregarlo al compose y validar la conectividad con el API Gateway creado en el Módulo 3.
Antes de agregar lógica de negocio (DDD, R2DBC, Kafka), necesitamos verificar que:
- El microservicio compila y arranca dentro de Docker
- Está visible en la red
arka-network - El API Gateway puede enrutar tráfico hacia él
5.1 Prerequisitos
- ✅ La infraestructura del Módulo 1 está corriendo (
docker compose ps) - ✅ El stack de CloudFormation del Módulo 3 fue desplegado (API Gateway existe)
- ✅ Tienes Java 17+ y Gradle 9.2+ instalados
# Verificar que el API Gateway existe
awslocal apigateway get-rest-apis --region us-east-1 --query 'items[].{Name:name, Id:id}' --output table
5.2 Actualizar las variables de entorno
Antes de crear el microservicio, agrega las variables del servicio al .env:
MS_ORDERS_PORT=8081
MS_ORDERS_HOST=arka-ms-orders
MS_PAYMENT_PORT=8083
MS_PAYMENT_HOST=arka-ms-payment
MS_PAYMENT_BASE_URL=http://ms-payment:8083
5.3 Crear el proyecto con el Scaffold
Desde la raíz de arka-lab, creamos el microservicio:
# Dentro de arka-lab/
mkdir ms-orders
cd ms-orders
Paso 1: Configurar el plugin
plugins {
id 'co.com.bancolombia.cleanArchitecture' version '4.1.0'
}
Paso 2: Generar el wrapper de Gradle
gradle wrapper
Paso 3: Generar la estructura del proyecto
./gradlew ca \
--package=co.com.arka.orders \
--type=reactive \
--name=MsOrders \
--lombok=true \
--java-version=17
Paso 4: Generar el Entry Point WebFlux
./gradlew gep --type webflux
Los tests del scaffold fallarán con nuestros cambios. Elimínalos:
find . -path "*/src/test/*" -name "*.java" -delete
5.4 Crear el endpoint de Health Check
5.4.1 Handler
package co.com.arka.orders.api;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.util.Map;
@Component
@RequiredArgsConstructor
public class Handler {
public Mono<ServerResponse> healthCheck(ServerRequest serverRequest) {
return ServerResponse.ok().bodyValue(Map.of(
"service", "ms-orders",
"status", "UP",
"timestamp", LocalDateTime.now().toString()
));
}
}
5.4.2 Router
package co.com.arka.orders.api;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
@Configuration
public class RouterRest {
@Bean
public RouterFunction<ServerResponse> routerFunction(Handler handler) {
return route(GET("/api/health"), handler::healthCheck);
}
}
5.5 Configurar application.yaml
server:
port: ${MS_ORDERS_PORT:8081}
spring:
application:
name: "MsOrders"
devtools:
add-properties: false
h2:
console:
enabled: true
path: "/h2"
profiles:
include: null
management:
endpoints:
web:
exposure:
include: "health,prometheus"
endpoint:
health:
probes:
enabled: true
cors:
allowed-origins: "http://localhost:4200,http://localhost:8080"
${MS_ORDERS_PORT:8081}El puerto se lee de la variable de entorno MS_ORDERS_PORT, con valor por defecto 8081. Esto permite cambiarlo desde el .env sin modificar el código. En Docker, la variable se inyecta vía env_file.
5.6 Dockerizar el microservicio
5.6.1 Dockerfile
# ── Stage 1: Build ──
FROM gradle:9.2-jdk21 AS builder
VOLUME /tmp
WORKDIR /myapp
COPY applications applications
COPY domain domain
COPY infrastructure infrastructure
COPY *.gradle .
COPY lombok.* .
COPY gradlew.* .
COPY gradle.* .
RUN gradle build -x test --no-daemon
# ── Stage 2: Run ──
FROM eclipse-temurin:21-jre-alpine
VOLUME /tmp
WORKDIR /myapprun
COPY --from=builder /myapp/applications/app-service/build/libs/*.jar MsOrders.jar
RUN apk update && apk add curl
ARG PORT=8081
ENV JAVA_OPTS=" -XX:+UseContainerSupport -XX:MaxRAMPercentage=70 -Djava.security.egd=file:/dev/./urandom"
ENV MS_ORDERS_PORT=${PORT}
EXPOSE ${MS_ORDERS_PORT}
ENTRYPOINT ["/bin/sh", "-c", "/opt/java/openjdk/bin/java $JAVA_OPTS -jar MsOrders.jar"]
apk add curlLa imagen eclipse-temurin:21-jre-alpine no incluye curl por defecto. Lo instalamos porque el healthcheck del compose usa curl para verificar que el servicio está listo.
5.7 Agregar ms-orders al Docker Compose
Agrega el siguiente servicio al compose.yaml existente, después del bloque de Traefik y antes de networks::
En este modulo puedes omitir temporalmente el bloque depends_on: ms-payment y la variable MS_PAYMENT_BASE_URL. Los agregaremos de forma definitiva en el Modulo 8 cuando el servicio exista.
# ═══════════════════════════════════════════════════
# MsOrders — Microservicio de Órdenes
# ═══════════════════════════════════════════════════
ms-orders:
build:
context: ./ms-orders
dockerfile: deployment/Dockerfile
args:
- PORT=${MS_ORDERS_PORT}
container_name: arka-ms-orders
ports:
- "${MS_ORDERS_PORT}:${MS_ORDERS_PORT}"
environment:
- MS_PAYMENT_BASE_URL=http://${MS_PAYMENT_HOST}:${MS_PAYMENT_PORT}
- MS_PAYMENT_PROCESS_PATH=/api/payments/process
- MS_PAYMENT_TIMEOUT_SECONDS=3
env_file:
- .env
depends_on:
postgres-orders:
condition: service_healthy
localstack:
condition: service_healthy
kafka:
condition: service_healthy
ms-payment:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${MS_ORDERS_PORT}/actuator/health"]
interval: 15s
timeout: 5s
retries: 5
start_period: 60s
networks:
- arka-network
| Configuración | Valor | ¿Por qué? |
|---|---|---|
env_file: .env | Inyecta todas las variables del .env | El microservicio lee MS_ORDERS_PORT desde ahí |
build.args.PORT | ${MS_ORDERS_PORT} | Se pasa al ARG PORT del Dockerfile para el EXPOSE |
container_name | arka-ms-orders | Es el hostname que usa el API Gateway (pOrdersServiceHost) |
healthcheck | /actuator/health | Endpoint de Spring Boot Actuator (se habilita automáticamente) |
start_period: 60s | Espera antes de chequear | El microservicio necesita tiempo para compilar y arrancar |
depends_on kafka | service_healthy | Garantiza que Kafka esté listo antes de iniciar |
Para que depends_on kafka: condition: service_healthy funcione, Kafka necesita tener su propio healthcheck definido. Agrégalo al servicio kafka en tu compose si aún no lo tienes:
healthcheck:
test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:29092", "--list"]
interval: 10s
timeout: 5s
retries: 10
start_period: 60s
5.8 Construir y Levantar
Paso 1: Reconstruir el compose
# Desde la raíz de arka-lab/
docker compose up -d --build ms-orders
La primera vez, Docker construirá la imagen desde cero descargando Gradle y las dependencias. Esto puede tomar varios minutos. Las siguientes ejecuciones serán más rápidas gracias al cache de capas.
Paso 2: Verificar que el servicio está corriendo
docker compose ps
Deberías ver arka-ms-orders en estado Up (healthy):
NAME STATUS
arka-db-orders Up (healthy)
arka-db-inventory Up (healthy)
arka-db-payment Up (healthy)
arka-kafka Up (healthy)
arka-kafka-ui Up
arka-localstack Up (healthy)
arka-traefik Up
arka-ms-orders Up (healthy) ← NUEVO
Paso 3: Probar el healthcheck directamente
curl http://localhost:8081/api/health | python3 -m json.tool
Respuesta esperada:
{
"service": "ms-orders",
"status": "UP",
"timestamp": "2026-03-01T..."
}
5.9 Probar el API Gateway → ms-orders
El API Gateway (creado en el Módulo 3) ya tiene una ruta /orders/{proxy+} configurada como HTTP_PROXY hacia http://arka-ms-orders:8081. Vamos a verificar la conectividad.
Paso 1: Obtener el ID del API Gateway
API_ID=$(awslocal apigateway get-rest-apis \
--region us-east-1 \
--query 'items[0].id' \
--output text)
echo "API Gateway ID: $API_ID"
Paso 2: Probar vía API Gateway
curl "https://${API_ID}.execute-api.localhost.localstack.cloud:4566/v1/orders/api/health" | python3 -m json.tool
Respuesta esperada:
{
"service": "ms-orders",
"status": "UP",
"timestamp": "2026-03-01T..."
}
curl → https://<api-id>.execute-api.localhost.localstack.cloud:4566
→ API Gateway → HTTP_PROXY → arka-ms-orders:8081 → /api/health
El request viajó: tu máquina → LocalStack (API Gateway) → red Docker → arka-ms-orders. Esto valida que el enrutamiento funciona de extremo a extremo.
5.10 ¿Qué acabamos de construir?
Verifica que puedas responder SÍ a todo:
- ¿El proyecto compila sin errores? (
docker compose up -d --build ms-orders) - ¿
docker compose psmuestraarka-ms-orderscomohealthy? - ¿
curl http://localhost:8081/api/healthresponde constatus: UP? - ¿La petición vía API Gateway también devuelve
status: UP?
Si todas las respuestas son SÍ, ms-orders está visible en la red Docker y accesible vía API Gateway. En los siguientes módulos agregaremos la lógica de negocio con DDD y la persistencia con R2DBC. 🚀
¿Qué aprendimos?
| Concepto | Lo que hicimos |
|---|---|
| Scaffold Bancolombia | Generamos ms-orders reactivo con Clean Architecture |
| WebFlux Entry Point | Endpoint /api/health con handler funcional |
| Multi-stage Dockerfile | Build con Gradle + ejecución con JRE Alpine + curl para healthcheck |
| Docker Compose | Integración con env_file, depends_on (healthy), y arka-network |
| API Gateway Proxy | Verificamos el enrutamiento HTTP_PROXY vía execute-api.localhost.localstack.cloud |
| Spring Boot Actuator | Healthcheck del compose usa /actuator/health |
Ahora que ms-orders está corriendo en Docker y accesible vía API Gateway, pasamos a modelar el dominio con DDD y Arquitectura Hexagonal.