Saltar al contenidoPedro Farbo

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.

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e

En 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ísticaDescripción
Alto RendimientoConstruido sobre Nginx/OpenResty, soporta millones de requests/segundo
Extensible100+ plugins oficiales y soporte para plugins personalizados (Lua, Go, JavaScript)
Cloud NativeIntegración nativa con Kubernetes, Helm charts oficiales
Open SourceVersión gratuita con todas las funcionalidades esenciales
Modo DB-lessPuede ejecutarse sin base de datos, usando solo configuración declarativa
Multi-protocoloHTTP, gRPC, WebSocket, TCP/UDP

Kong vs Alternativas

GatewayFortalezasDebilidades
KongRendimiento, extensibilidad, comunidadCurva de aprendizaje
AWS API GatewayIntegración AWS, serverlessVendor lock-in, costo
TraefikSimple, auto-discoveryMenos plugins
NGINXRendimientoRequiere más configuración manual
EnvoyService mesh, observabilidadComplejidad

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)

yaml
# 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: bridge

Configuración Declarativa (DB-less)

yaml
# 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: 3600

Implementación de Plugins

1. Autenticación JWT

yaml
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: true

2. Rate Limiting Avanzado

yaml
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: redis

3. Plugin de Circuit Breaker

lua
-- 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 CircuitBreakerHandler

Observabilidad

Métricas Prometheus

yaml
plugins:  - name: prometheus    config:      per_consumer: true      status_code_metrics: true      latency_metrics: true      bandwidth_metrics: true      upstream_health_metrics: true

Configuración de Alertas

yaml
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: critical

Despliegue en Kubernetes

Instalación con Helm

bash
helm repo add kong https://charts.konghq.comhelm repo update helm install kong kong/kong \  --namespace kong \  --create-namespace \  --values values.yaml

Kong Ingress Controller

yaml
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: 3000

Tests

Tests de Integración

typescript
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)

javascript
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:

  1. Rendimiento: Millones de requests por segundo
  2. Flexibilidad: 100+ plugins y soporte para personalización
  3. Observabilidad: Métricas, logs y tracing integrados
  4. Seguridad: Autenticación, autorización y rate limiting
  5. 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.

PF
Sobre el autor

Pedro Farbo

Platform Engineering Lead & Solutions Architect con +10 años de experiencia. CEO de Farbo TSC. Especialista en Microservicios, Kong, Backstage y Cloud.

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e