S4 - Punto único de acceso y distribución de tráfico
1. Introducción
Tiempo: 20 min.
1.1 Propósito
Incorporar un punto único de acceso para que los clientes consuman el sistema mediante Gateway y para distribuir tráfico entre instancias disponibles.
1.2 Resultado de aprendizaje
El estudiante configura rutas en Gateway, consume microservicios mediante un acceso centralizado y evidencia balanceo de carga.
1.3 Producto de sesión
Gateway operativo en infra/gateway, con rutas hacia microservicios registrados en Eureka y pruebas de distribución de tráfico.
1.4 Motivacion de la sesión
Si un cliente conoce directamente todos los microservicios, queda acoplado a sus puertos, rutas y ubicaciones. Un Gateway permite centralizar el acceso y esconder la topología interna del sistema.
Preguntas para los estudiantes:
- Por qué el cliente no debería conocer todos los microservicios?
- Qué problema aparece si cada cliente llama directamente a cada microservicio?
- Cómo se demuestra que existe balanceo de carga?
1.5 Ubicación en el curso
- Unidad: U1 - Sistema distribuido base orientado a producción.
- Producto de unidad: sistema distribuido base funcional, configurable y preparado para múltiples instancias.
- Avance del producto en esta sesión: acceso centralizado con rutas y balanceo de carga.
Roadmap para elaborar el producto de la unidad:
flowchart TB
Cliente["Cliente de prueba<br/>PowerShell / bash / Swagger"]
Gateway["Gateway<br/>punto único de acceso<br/>balanceo de carga<br/>HOY"]
Catalogo["catalogo-ms<br/>construido"]
Producto["producto-ms<br/>trabajo aplicado"]
Eureka["Registro de servicios<br/>Eureka<br/>construido"]
Config["Servidor de configuración<br/>Config Server<br/>construido"]
Cliente --> Gateway
Gateway --> Catalogo
Gateway --> Producto
Gateway -. descubre servicios .-> Eureka
Catalogo -. registra instancia .-> Eureka
Producto -. registra instancia .-> Eureka
Gateway -. carga configuracion .-> Config
Catalogo -. carga configuracion .-> Config
Producto -. carga configuracion .-> Config
classDef done fill:#e8f5e9,stroke:#2e7d32,color:#111;
classDef today fill:#ffe08a,stroke:#9a6b00,stroke-width:2px,color:#111;
class Catalogo,Eureka,Config done;
class Gateway today;
2. Explica
Tiempo: 15 min.
2.1 Conceptos clave
- Gateway: punto único de entrada al sistema.
- Ruta: regla que dirige una petición hacia un servicio.
- Load Balancer: selecciona una instancia disponible del servicio.
lb://: esquema usado para resolver servicios registrados por nombre lógico.
2.2 Arquitectura del producto en ecom
2.2.1 Gateway y balanceo en DEV
flowchart TB
Cliente["Cliente<br/>PowerShell / bash / navegador"]
Config["Config Server<br/>localhost:18888"]
Gateway["API Gateway<br/>localhost:18080"]
Eureka["Eureka Server<br/>localhost:18761"]
Catalogo1["catalogo-ms<br/>instancia 1<br/>puerto dinamico"]
Catalogo2["catalogo-ms<br/>instancia 2<br/>puerto dinamico"]
Cliente --> Gateway
Cliente -->|"GET localhost:18080/actuator/health"| Gateway
Gateway -. "spring.config.import<br/>http://localhost:18888" .-> Config
Gateway -. "descubre servicios<br/>http://localhost:18761/eureka" .-> Eureka
Catalogo1 -. "registra instancia<br/>http://localhost:18761/eureka" .-> Eureka
Catalogo2 -. "registra instancia<br/>http://localhost:18761/eureka" .-> Eureka
Gateway -->|"lb://CATALOGO-MS"| Catalogo1
Gateway -->|"lb://CATALOGO-MS"| Catalogo2
2.2.2 Gateway y balanceo en PROD local
flowchart TB
Cliente["Cliente<br/>PowerShell / bash / navegador"]
subgraph Docker["Docker Network: ecom-prod-net"]
Config["ecom-config<br/>8888 interno"]
Gateway["ecom-gateway<br/>8080 interno"]
Eureka["eureka<br/>8761 interno"]
Catalogo1["catalogo-ms<br/>instancia 1<br/>8080 interno"]
Catalogo2["catalogo-ms<br/>instancia 2<br/>8080 interno"]
end
Cliente -->|"GET localhost:28082/actuator/health"| Gateway
Cliente -->|"GET localhost:28082/api/v1/categorías"| Gateway
Gateway -. "spring.config.import<br/>http://ecom-config:8888" .-> Config
Gateway -. "descubre servicios<br/>http://eureka:8761/eureka" .-> Eureka
Catalogo1 -. "registra instancia<br/>http://eureka:8761/eureka" .-> Eureka
Catalogo2 -. "registra instancia<br/>http://eureka:8761/eureka" .-> Eureka
Gateway -->|"lb://CATALOGO-MS"| Catalogo1
Gateway -->|"lb://CATALOGO-MS"| Catalogo2
2.2.3 Estado nuevo de URLs en S4
| Ambiente | Componente | URL o nombre |
|---|---|---|
| DEV | Gateway | http://localhost:18080 |
| DEV | Gateway health | http://localhost:18080/actuator/health |
| DEV | Eureka | http://localhost:18761 |
| PROD local | Gateway desde host | http://localhost:28082 |
| PROD local | Gateway health | http://localhost:28082/actuator/health |
| PROD local | Eureka desde host | http://localhost:28761 |
| PROD local | Gateway interno | http://ecom-gateway:8080 |
| PROD local | Eureka interno | http://eureka:8761/eureka |
2.3 Observabilidad y diagnóstico
Señales a revisar:
- Health de Gateway.
- Eureka con servicios registrados.
- Logs de rutas.
- Respuestas repetidas desde instancias distintas.
Errores frecuentes:
| Problema | Causa probable | Solución |
|---|---|---|
| 503 | Servicio no registrado o Eureka no disponible | Revisar Eureka y registros |
| 404 | Ruta mal configurada | Revisar predicates y paths |
| No balancea | Solo existe una instancia | Levantar otra instancia |
3. Aplica: actividad práctica guiada
Tiempo: 3h.
En el laboratorio, el docente guía la configuración de Gateway y la prueba de rutas hacia microservicios registrados.
La ruta principal de la sesión es construir desde cero. Si el estudiante necesita avanzar más rápido, puede usar la ruta alternativa del paso 3.17 para clonar el tag final y ejecutar las pruebas.
3.1 Crear carpeta del Gateway
Producto del paso: ubicación del proyecto Gateway preparada dentro del monorepo.
En el monorepo ecom, Gateway vive en:
infra/gateway
Desde la raiz del repositorio:
PowerShell / bash macOS/Linux:
mkdir infra/gateway
Luego abre la raiz del monorepo en VS Code:
code .
3.2 Crear proyecto Spring Boot Gateway desde VS Code
Producto del paso: proyecto Spring Boot ecom-gateway creado dentro de infra/gateway.
En VS Code usa Spring Initializr:
Spring Initializr: Create a Maven Project
Spring Boot: 3.5.x
Language: Java 17
Group Id: com.upeu
Artifact Id: ecom-gateway
Package name: com.upeu.gateway
Packaging: Jar
Ubicación: infra/gateway
Dependencias para S04:
| Grupo | Dependencias | Propósito |
|---|---|---|
| Spring Cloud | Gateway | Punto único de acceso |
| Spring Cloud | Eureka Discovery Client | Resolver servicios registrados |
| Spring Cloud | Config Client | Leer rutas desde Config Server |
| Operación | Actuator | Health y diagnóstico |
| Desarrollo | DevTools | Recarga durante desarrollo |
En S07 se agregará seguridad al Gateway. En esta sesión todavía se trabaja el acceso único y el balanceo.
3.3 Ajustar pom.xml
Producto del paso: Gateway con Spring Cloud y dependencias necesarias para DEV.
En infra/gateway/pom.xml, confirma o agrega la versión de Spring Cloud:
<properties>
<java.version>17</java.version>
<spring-cloud.version>2025.0.2</spring-cloud.version>
</properties>
Agrega las dependencias principales:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway-server-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Agrega el BOM de Spring Cloud:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.4 Configurar application.yml base de Gateway
Producto del paso: Gateway preparado para leer rutas desde Config Server.
En infra/gateway/src/main/resources/application.yml:
server:
port: 18080
spring:
application:
name: gateway
profiles:
active: dev
config:
import: "optional:configserver:${CONFIG_SERVER_URL:http://localhost:18888}"
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: always
logging:
level:
root: INFO
3.5 Crear rutas desde Config Server
Producto del paso: archivos de configuración externa del Gateway creados en config-repo.
Crea el archivo DEV:
infra/config/config-repo/gateway-dev.yml
Pega este contenido:
spring:
cloud:
gateway:
routes:
- id: catalogo-route
uri: lb://catalogo-ms
predicates:
- Path=/api/v1/categorias/**
- id: catalogo-instancia
uri: lb://catalogo-ms
predicates:
- Path=/api/v1/catalogo/instancia
- id: producto-route
uri: lb://producto-ms
predicates:
- Path=/api/v1/productos/**
- id: producto-instancia
uri: lb://producto-ms
predicates:
- Path=/api/v1/producto/instancia
eureka:
instance:
hostname: localhost
prefer-ip-address: false
instance-id: ${spring.application.name}:${local.server.port:${server.port}}
metadata-map:
instance-port: ${local.server.port:${server.port}}
client:
service-url:
defaultZone: http://localhost:18761/eureka
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
Crea el archivo PROD:
infra/config/config-repo/gateway-prod.yml
Pega este contenido:
spring:
cloud:
gateway:
routes:
- id: catalogo-route
uri: lb://catalogo-ms
predicates:
- Path=/api/v1/categorias/**
- id: catalogo-instancia
uri: lb://catalogo-ms
predicates:
- Path=/api/v1/catalogo/instancia
- id: producto-route
uri: lb://producto-ms
predicates:
- Path=/api/v1/productos/**
- id: producto-instancia
uri: lb://producto-ms
predicates:
- Path=/api/v1/producto/instancia
eureka:
client:
service-url:
defaultZone: http://eureka:8761/eureka
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: never
Las rutas apuntan a nombres lógicos registrados en Eureka. Por eso el Gateway no necesita conocer el puerto dinamico de cada instancia.
3.6 Levantar Config Server en DEV
Producto del paso: configuración externa disponible por HTTP.
PowerShell / bash macOS/Linux:
cd infra/config
mvn spring-boot:run
3.7 Probar configuración de Gateway desde Config Server
Producto del paso: confirmar que gateway-dev.yml y gateway-prod.yml son leidos por Config Server.
PowerShell:
Invoke-RestMethod -Method Get -Uri "http://localhost:18888/gateway/dev"
Invoke-RestMethod -Method Get -Uri "http://localhost:18888/gateway/prod"
bash macOS/Linux:
curl http://localhost:18888/gateway/dev
curl http://localhost:18888/gateway/prod
Resultado esperado:
- La respuesta indica
name: gateway. - Se observan rutas hacia servicios con
lb://. - En DEV aparece Eureka con
localhost:18761. - En PROD aparece Eureka con
http://eureka:8761/eureka.
3.8 Levantar Eureka en DEV
Producto del paso: registro de servicios disponible para Gateway.
En otra terminal:
cd infra/eureka
mvn spring-boot:run
Verifica en navegador:
http://localhost:18761
3.9 Levantar Gateway en DEV
Producto del paso: Gateway ejecutando en localhost:18080.
En otra terminal:
cd infra/gateway
mvn spring-boot:run
3.10 Verificar Gateway en DEV
PowerShell:
Invoke-RestMethod -Method Get -Uri "http://localhost:18080/actuator/health"
bash macOS/Linux:
curl http://localhost:18080/actuator/health
Resultado esperado: estado UP.
3.11 Levantar microservicio y segunda instancia
Producto del paso: catalogo-ms registrado con más de una instancia.
PowerShell / bash macOS/Linux:
cd services/catalogo-ms
docker compose -f compose-dev.yml up -d
mvn spring-boot:run
En otra terminal:
cd services/catalogo-ms
mvn spring-boot:run
3.12 Verificar registro en Eureka
Abre:
http://localhost:18761
Resultado esperado:
CATALOGO-MSaparece registrado.- Hay dos instancias si se levantaron dos terminales.
3.13 Probar por Gateway
Producto del paso: el cliente consume catalogo-ms por Gateway y no por el puerto directo del microservicio.
PowerShell:
Invoke-RestMethod -Method Get -Uri "http://localhost:18080/actuator/health"
Invoke-RestMethod -Method Get -Uri "http://localhost:18080/api/v1/categorias"
bash macOS/Linux:
curl http://localhost:18080/actuator/health
curl http://localhost:18080/api/v1/categorias
3.14 Evidenciar balanceo
Producto del paso: se observa distribución de tráfico entre instancias disponibles.
El endpoint de instancia debe existir en catalogo-ms. Si todavía no lo tienes, crea este controlador:
services/catalogo-ms/src/main/java/com/upeu/catálogo/controller/GatewayInstanciasController.java
Pega este código:
package com.upeu.catalogo.controller;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/catalogo")
@RequiredArgsConstructor
public class GatewayInstanciasController {
private final Environment environment;
@GetMapping("/instancia")
public Map<String, String> instancia() {
return Map.of(
"servicio", "catalogo-ms",
"instancia", environment.getProperty("local.server.port", "N/A"),
"serverPort", environment.getProperty("server.port", "N/A"),
"host", hostName());
}
private String hostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return "unknown";
}
}
}
Ejecuta varias veces por Gateway:
PowerShell:
1..10 | ForEach-Object {
Invoke-RestMethod -Method Get -Uri "http://localhost:18080/api/v1/catalogo/instancia"
}
bash macOS/Linux:
for i in {1..10}; do
curl http://localhost:18080/api/v1/catalogo/instancia
echo
done
Resultado esperado:
- Gateway responde.
- Eureka muestra instancias disponibles.
- Las respuestas repetidas alternan entre instancias o muestran puertos distintos.
3.15 Probar error esperado
Producto del paso: estudiante diferencia una falla de ruta y una falla de disponibilidad.
Deten una instancia o cambia temporalmente una ruta para observar:
503cuando no hay servicio disponible.404cuando la ruta no coincide.
Luego restaura la configuración.
3.16 Preparar, levantar y probar PROD local
En este paso se cierra la sesión mostrando que el Gateway también funciona en producción local con Docker. Primero se prepara soporte Docker, luego se levanta infraestructura y finalmente se prueba el acceso por Gateway.
3.16.1 Crear soporte Docker para Gateway
Producto del paso: Gateway preparado para ejecutarse dentro de Docker junto con config y eureka.
Crea infra/gateway/Dockerfile:
FROM maven:3.9.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn -q -DskipTests dependency:go-offline
COPY src ./src
RUN mvn -q clean package -DskipTests
FROM eclipse-temurin:17-jre
WORKDIR /app
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
En infra/compose.yml, agrega el servicio gateway:
gateway:
build:
context: ./gateway
dockerfile: Dockerfile
container_name: ecom-gateway
restart: unless-stopped
ports:
- "28082:8080"
environment:
SERVER_PORT: 8080
SPRING_PROFILES_ACTIVE: prod
CONFIG_SERVER_URL: http://ecom-config:8888
depends_on:
config:
condition: service_healthy
eureka:
condition: service_healthy
networks:
- ecom-prod-net
3.16.2 Levantar Gateway en PROD local
En PROD local, primero se levanta infraestructura:
infra -> ecom-config + eureka + ecom-gateway
Luego se levantan microservicios:
services/catalogo-ms -> BD + catálogo-ms
PowerShell / bash macOS/Linux:
cd infra
docker compose up -d --build config eureka gateway
docker compose ps
Verifica con PowerShell:
Invoke-RestMethod -Method Get -Uri "http://localhost:28082/actuator/health"
Invoke-RestMethod -Method Get -Uri "http://localhost:28761/actuator/health"
Verifica con bash macOS/Linux:
curl http://localhost:28082/actuator/health
curl http://localhost:28761/actuator/health
3.16.3 Levantar microservicio en PROD local y probar Gateway
Producto del paso: acceso funcional a catalogo-ms por Gateway PROD.
PowerShell / bash macOS/Linux:
cd ../services/catalogo-ms
docker compose up -d --build --scale catalogo-ms=2
Prueba desde el host por Gateway con PowerShell:
Invoke-RestMethod -Method Get -Uri "http://localhost:28082/api/v1/categorias"
Prueba desde el host por Gateway con bash macOS/Linux:
curl http://localhost:28082/api/v1/categorias
Resultado esperado:
- Gateway PROD responde por
localhost:28082. - Microservicios no exponen puerto host fijo.
- El acceso funcional pasa por Gateway.
3.16.4 Validar evidencias de cierre de la práctica
Antes de pasar a la actividad autónoma, verifica:
- Gateway DEV health.
- Ruta DEV por Gateway.
- Eureka con múltiples instancias.
- Gateway PROD health.
- Ruta PROD por Gateway.
- Diagnóstico de 404 o 503 explicado.
3.17 Ruta alternativa: clonar y ejecutar a partir del tag final de la sesión
PowerShell / bash macOS/Linux:
git clone --branch vs04-gateway-load-balancer https://github.com/261dist/ecom.git ecom-s04
cd ecom-s04
4. Crea: actividad autónoma
Tiempo: 4h fuera del aula.
Esta actividad autónoma se desarrolla sobre el proyecto de fin de curso del equipo. El producto de la unidad se construye por acumulacion de los avances de cada sesión; por eso, la evidencia de esta sesión debe incorporarse a la documentación del proyecto y quedar trazable en GitHub.
4.1 Plantilla de evidencia individual
Entrega un PDF con el siguiente nombre:
El PDF de esta sesión debe generarse como impresion o exportacion de la sección correspondiente en MkDocs o una herramienta equivalente. No se acepta un PDF armado manualmente fuera de la documentación del proyecto.
S04_Equipo##_ApellidoNombre.pdf
4.1.1 Datos del estudiante
- Nombre:
- Equipo:
- Sesión: S04 - Punto único de acceso y distribución de tráfico
- Rol o aporte realizado:
- Link de GitHub:
4.1.2 Trabajo autónomo realizado
- Agregar o revisar una ruta en Gateway.
- Probar un endpoint mediante Gateway.
- Levantar múltiples instancias de un microservicio.
- Evidenciar balanceo o explicar el diagnóstico.
- Documentar un error frecuente y su solución.
4.1.3 Evidencia técnica
- Gateway activo.
- Ruta probada por Gateway.
- Eureka con instancias.
- Balanceo evidenciado.
- Registro en base de datos si la prueba modifica datos.
4.1.4 Error o hallazgo
Describe un 404, 503, error de ruta, servicio no registrado o problema de balanceo.
4.1.5 Reflexión técnica breve
Explica por qué Gateway permite ocultar la topología interna del sistema.
4.2 Criterios mínimos de aceptación
- PDF con nombre correcto.
- Evidencia de Gateway activo.
- Ruta probada.
- Eureka con servicio registrado.
- Aporte individual verificable.
5. Cierre evaluativo
Tiempo: 20 min.
5.1 Resultados esperados
- Gateway ejecuta en DEV.
- Rutas consumen microservicios por nombre lógico.
- Se evidencia distribución de tráfico.
- El estudiante diagnostica errores 404 y 503.
5.2 Evidencia del producto de sesión
Cada estudiante entrega un PDF individual siguiendo la plantilla de la sección 4.1.
Nombre del archivo:
S04_Equipo##_ApellidoNombre.pdf
5.3 Preguntas de defensa y reflexión
- Por qué el cliente debe entrar por Gateway?
- Qué significa
lb://? - Cómo se relacionan Gateway y Eureka?
- Cómo diagnosticas un 503?
- Cómo evidencias balanceo?
5.4 Rúbrica de evaluación
| Dimensión | Peso | 3 - Logro destacado | 2 - Logro | 1 - Proceso | 0 - Inicio | Puntuación obtenida |
|---|---|---|---|---|---|---|
| 1. Gateway operativo | 2 | Evidencia Gateway activo, health y rutas funcionales. | Evidencia Gateway activo y una ruta funcional. | Evidencia parcial o sin prueba clara. | No evidencia Gateway funcionando. | |
| 2. Rutas centralizadas | 2 | Configura y explica rutas por nombre lógico. | Evidencia rutas funcionales. | Rutas incompletas o confusas. | No evidencia rutas. | |
| 3. Balanceo de carga | 2 | Evidencia distribución entre múltiples instancias. | Evidencia múltiples instancias y prueba parcial. | Explica balanceo sin evidencia suficiente. | No evidencia balanceo. | |
| 4. Diagnóstico técnico | 2 | Analiza errores de Gateway/Eureka con solución. | Explica error y causa probable. | Menciona error sin análisis. | No presenta diagnóstico. | |
| 5. Aporte individual | 1 | Aporte claro, verificable y conectado al producto. | Aporte identificable. | Aporte general. | No se identifica aporte. | |
| 6. Orden y reflexión | 1 | PDF ordenado, evidencias legibles y reflexión técnica clara. | Evidencias entendibles y reflexión suficiente. | Evidencias poco claras o reflexión superficial. | PDF desordenado o sin reflexión. |
Puntuación acumulada = suma de (Peso * Puntuacion obtenida) = ____.
Nota final = (Puntuacion acumulada / 30) * 20 = ____.
Para usar la rúbrica con IA, solicita:
Evalúa el PDF usando la rúbrica de la sesión.
Para cada dimensión selecciona la puntuación obtenida usando la escala Inicio=0, Proceso=1, Logro=2, Logro destacado=3.
Justifica brevemente cada puntuación.
Calcula la puntuación acumulada con la fórmula: suma de (Peso * Puntuación obtenida).
Calcula la nota final sobre 20 con la fórmula: (Puntuación acumulada / 30) * 20.
Indica 2 fortalezas y 2 recomendaciones.