API Gateway con Kong: Guía Completa para Microservicios
Aprende a implementar un API Gateway robusto con Kong para gestionar tus microservicios, incluyendo autenticación, rate limiting, load balancing y observabilidad.
¡Este contenido es gratuito! Ayuda a mantener el proyecto en línea.
0737160d-e98f-4a65-8392-5dba70e7ff3eEn el artículo anterior sobre microservicios, construimos un servicio de usuarios siguiendo Clean Architecture y DDD. Ahora, vamos a implementar un API Gateway con Kong para gestionar la comunicación entre clientes y nuestros microservicios.
¿Qué es un API Gateway?
Un API Gateway es el punto de entrada único para todas las solicitudes de clientes a tus microservicios. Actúa como un proxy inverso que enruta solicitudes, agrega respuestas y proporciona funcionalidades cross-cutting.
┌─────────────────────────────────────────────────────────────────────┐
│ Clients │
│ (Web, Mobile, IoT, Partners) │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ API Gateway (Kong) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
│ │ Auth │ │ Rate │ │ Load │ │ Logging │ │ Request │ │
│ │ │ │ Limiting│ │Balancing│ │ │ │ Transform │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ User │ │ Order │ │ Product │
│ Service │ │ Service │ │ Service │
└──────────┘ └──────────┘ └──────────┘
¿Por qué Kong?
Kong es uno de los API Gateways más populares y robustos del mercado:
Beneficios
| Característica | Descripción |
|---|---|
| Alto Rendimiento | Construido sobre Nginx/OpenResty, soporta millones de requests/segundo |
| Extensible | 100+ plugins oficiales y soporte para plugins personalizados (Lua, Go, JavaScript) |
| Cloud Native | Integración nativa con Kubernetes, Helm charts oficiales |
| Open Source | Versión gratuita con todas las funcionalidades esenciales |
| Modo DB-less | Puede ejecutarse sin base de datos, usando solo configuración declarativa |
| Multi-protocolo | HTTP, gRPC, WebSocket, TCP/UDP |
Kong vs Alternativas
| Gateway | Fortalezas | Debilidades |
|---|---|---|
| Kong | Rendimiento, extensibilidad, comunidad | Curva de aprendizaje |
| AWS API Gateway | Integración AWS, serverless | Vendor lock-in, costo |
| Traefik | Simple, auto-discovery | Menos plugins |
| NGINX | Rendimiento | Requiere más configuración manual |
| Envoy | Service mesh, observabilidad | Complejidad |
Arquitectura de Kong
┌─────────────────────────────────────────────────────────────────┐
│ Kong Gateway │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Kong Proxy │ │
│ │ (Port 8000/8443) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Plugin │→ │ Plugin │→ │ Plugin │→ │ Plugin │→ ... │ │
│ │ │ Auth │ │ Rate │ │ Log │ │Transform│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Kong Admin API │ │
│ │ (Port 8001/8444) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Data Store │ │
│ │ (PostgreSQL / Cassandra / DB-less) │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Conceptos Fundamentales
- Services: Representan tus microservicios upstream
- Routes: Definen cómo las solicitudes llegan a los services
- Consumers: Representan usuarios o aplicaciones que consumen tus APIs
- Plugins: Agregan funcionalidades (auth, rate limiting, logging, etc.)
- Upstreams: Definen load balancing y health checks
Estructura del Proyecto
kong-gateway/
├── docker/
│ ├── docker-compose.yml
│ ├── docker-compose.dev.yml
│ └── docker-compose.prod.yml
│
├── kong/
│ ├── kong.yml # Configuración declarativa
│ ├── kong.conf # Configuración de Kong
│ │
│ ├── plugins/ # Plugins personalizados
│ │ └── custom-auth/
│ │ ├── handler.lua
│ │ └── schema.lua
│ │
│ └── templates/
│ └── nginx.conf
│
├── config/
│ ├── services/
│ │ ├── user-service.yml
│ │ ├── order-service.yml
│ │ └── product-service.yml
│ │
│ ├── routes/
│ │ ├── user-routes.yml
│ │ ├── order-routes.yml
│ │ └── product-routes.yml
│ │
│ ├── plugins/
│ │ ├── global-plugins.yml
│ │ ├── auth-plugins.yml
│ │ └── rate-limiting.yml
│ │
│ └── consumers/
│ ├── mobile-app.yml
│ ├── web-app.yml
│ └── partners.yml
│
├── scripts/
│ ├── setup.sh
│ ├── deploy.sh
│ ├── backup.sh
│ └── health-check.sh
│
├── k8s/
│ ├── namespace.yaml
│ ├── kong-deployment.yaml
│ ├── kong-service.yaml
│ ├── kong-ingress.yaml
│ ├── configmap.yaml
│ └── secrets.yaml
│
├── monitoring/
│ ├── prometheus/
│ │ └── kong-metrics.yml
│ └── grafana/
│ └── kong-dashboard.json
│
├── tests/
│ ├── integration/
│ │ ├── auth.test.js
│ │ ├── rate-limiting.test.js
│ │ └── routing.test.js
│ └── load/
│ └── k6-load-test.js
│
├── Makefile
└── README.md
Instalación y Configuración
Docker Compose (Desarrollo)
# docker/docker-compose.ymlversion: '3.8' services: kong-database: image: postgres:15-alpine container_name: kong-database environment: POSTGRES_USER: kong POSTGRES_PASSWORD: kongpass POSTGRES_DB: kong volumes: - kong_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U kong"] interval: 5s timeout: 5s retries: 5 networks: - kong-net kong-migrations: image: kong:3.5-alpine container_name: kong-migrations command: kong migrations bootstrap depends_on: kong-database: condition: service_healthy environment: KONG_DATABASE: postgres KONG_PG_HOST: kong-database KONG_PG_USER: kong KONG_PG_PASSWORD: kongpass KONG_PG_DATABASE: kong networks: - kong-net restart: on-failure kong: image: kong:3.5-alpine container_name: kong depends_on: kong-migrations: condition: service_completed_successfully environment: KONG_DATABASE: postgres KONG_PG_HOST: kong-database KONG_PG_USER: kong KONG_PG_PASSWORD: kongpass KONG_PG_DATABASE: kong KONG_PROXY_ACCESS_LOG: /dev/stdout KONG_ADMIN_ACCESS_LOG: /dev/stdout KONG_PROXY_ERROR_LOG: /dev/stderr KONG_ADMIN_ERROR_LOG: /dev/stderr KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl ports: - "8000:8000" - "8443:8443" - "8001:8001" - "8444:8444" healthcheck: test: ["CMD", "kong", "health"] interval: 10s timeout: 10s retries: 10 networks: - kong-net restart: unless-stopped volumes: kong_data: networks: kong-net: driver: bridgeConfiguración Declarativa (DB-less)
# kong/kong.yml_format_version: "3.0"_transform: true services: - name: user-service url: http://user-service:3000 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 tags: - internal - users - name: order-service url: http://order-service:3001 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 - name: product-service url: http://product-service:3002 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 routes: - name: user-api service: user-service paths: - /api/v1/users methods: - GET - POST - PUT - DELETE - PATCH strip_path: false preserve_host: true - name: order-api service: order-service paths: - /api/v1/orders methods: - GET - POST - PUT - DELETE - name: product-api service: product-service paths: - /api/v1/products methods: - GET - POST - PUT - DELETE upstreams: - name: user-service-upstream algorithm: round-robin healthchecks: active: healthy: interval: 5 successes: 2 unhealthy: interval: 5 http_failures: 3 http_path: /health/live timeout: 3 targets: - target: user-service-1:3000 weight: 100 - target: user-service-2:3000 weight: 100 consumers: - username: mobile-app custom_id: mobile-app-001 - username: web-app custom_id: web-app-001 - username: partner-api custom_id: partner-001 plugins: - name: correlation-id config: header_name: X-Correlation-ID generator: uuid echo_downstream: true - name: cors config: origins: - "https://app.example.com" methods: - GET - POST - PUT - DELETE - OPTIONS credentials: true max_age: 3600Implementación de Plugins
1. Autenticación JWT
plugins: - name: jwt route: user-api config: key_claim_name: kid claims_to_verify: - exp header_names: - Authorization maximum_expiration: 86400 - name: key-auth route: partner-api config: key_names: - X-API-Key hide_credentials: true2. Rate Limiting Avanzado
plugins: - name: rate-limiting-advanced config: limit: - 1000 window_size: - 60 window_type: sliding strategy: redis redis: host: redis port: 6379 - name: rate-limiting route: user-auth config: minute: 10 hour: 100 policy: redis3. Plugin de Circuit Breaker
-- kong/plugins/circuit-breaker/handler.lualocal CircuitBreakerHandler = { VERSION = "1.0.0", PRIORITY = 900,} local CLOSED = "CLOSED"local OPEN = "OPEN"local HALF_OPEN = "HALF_OPEN" local function get_circuit_state(conf, service_id) local cache_key = "circuit:" .. service_id local state = kong.cache:get(cache_key) return state or { status = CLOSED, failures = 0, last_failure = 0 }end function CircuitBreakerHandler:access(conf) local service_id = kong.router.get_service().id local state = get_circuit_state(conf, service_id) if state.status == OPEN then local now = ngx.now() if now - state.last_failure > conf.reset_timeout then state.status = HALF_OPEN else return kong.response.exit(503, { message = "Service temporarily unavailable", circuit_state = OPEN }) end endend return CircuitBreakerHandlerObservabilidad
Métricas Prometheus
plugins: - name: prometheus config: per_consumer: true status_code_metrics: true latency_metrics: true bandwidth_metrics: true upstream_health_metrics: trueConfiguración de Alertas
groups: - name: kong-alerts rules: - alert: KongHighLatency expr: histogram_quantile(0.95, rate(kong_latency_bucket[5m])) > 1000 for: 5m labels: severity: warning - alert: KongHighErrorRate expr: | sum(rate(kong_http_requests_total{code=~"5.."}[5m])) / sum(rate(kong_http_requests_total[5m])) > 0.05 for: 5m labels: severity: critical - alert: KongUpstreamDown expr: kong_upstream_target_health == 0 for: 1m labels: severity: criticalDespliegue en Kubernetes
Instalación con Helm
helm repo add kong https://charts.konghq.comhelm repo update helm install kong kong/kong \ --namespace kong \ --create-namespace \ --values values.yamlKong Ingress Controller
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: api-ingress annotations: konghq.com/strip-path: "false" konghq.com/plugins: rate-limiting,jwt-authspec: ingressClassName: kong tls: - hosts: - api.example.com secretName: api-tls rules: - host: api.example.com http: paths: - path: /api/v1/users pathType: Prefix backend: service: name: user-service port: number: 3000Tests
Tests de Integración
describe('Kong API Gateway', () => { describe('Routing', () => { it('should route requests to user service', async () => { const response = await axios.get(`${KONG_URL}/api/v1/users`); expect(response.status).toBe(200); }); }); describe('Authentication', () => { it('should reject requests without JWT', async () => { try { await axios.get(`${KONG_URL}/api/v1/users`); } catch (error: any) { expect(error.response.status).toBe(401); } }); }); describe('Rate Limiting', () => { it('should enforce rate limits', async () => { const requests = Array(15).fill(null).map(() => axios.get(`${KONG_URL}/api/v1/auth/login`, { validateStatus: () => true }) ); const responses = await Promise.all(requests); const rateLimited = responses.filter(r => r.status === 429); expect(rateLimited.length).toBeGreaterThan(0); }); });});Tests de Carga (k6)
import http from 'k6/http';import { check, sleep } from 'k6'; export const options = { stages: [ { duration: '1m', target: 50 }, { duration: '5m', target: 100 }, { duration: '1m', target: 200 }, { duration: '1m', target: 0 }, ], thresholds: { http_req_duration: ['p(95)<500'], errors: ['rate<0.01'], },}; export default function () { const response = http.get(`${BASE_URL}/api/v1/users`, { headers: { 'Authorization': `Bearer ${TOKEN}` } }); check(response, { 'status is 200': (r) => r.status === 200, }); sleep(1);}Checklist de Producción
Seguridad
- TLS/SSL configurado en todos los puertos
- Admin API protegida (no expuesta públicamente)
- Secrets gestionados via Vault/K8s Secrets
- Rate limiting habilitado
- CORS configurado correctamente
Rendimiento
- Connection pooling configurado
- Timeouts ajustados por servicio
- Cache habilitado donde sea apropiado
- Compresión gzip habilitada
Resiliencia
- Health checks configurados
- Circuit breaker implementado
- Retry policies configuradas
- Load balancing activo
Observabilidad
- Métricas Prometheus expuestas
- Logs estructurados
- Distributed tracing habilitado
- Alertas configuradas
Conclusión
Un API Gateway bien implementado es fundamental para una arquitectura de microservicios robusta. Kong proporciona una base sólida con:
- Rendimiento: Millones de requests por segundo
- Flexibilidad: 100+ plugins y soporte para personalización
- Observabilidad: Métricas, logs y tracing integrados
- Seguridad: Autenticación, autorización y rate limiting
- Resiliencia: Circuit breaker, retry y health checks
En el próximo artículo, aprende a implementar Mensajería con RabbitMQ para comunicación asíncrona entre microservicios.
¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!
0737160d-e98f-4a65-8392-5dba70e7ff3e