API Gateway com Kong: Guia Completo para Microserviços
Aprenda a implementar um API Gateway robusto com Kong para gerenciar seus microserviços, incluindo autenticação, rate limiting, load balancing e observabilidade.
Este conteúdo é gratuito! Ajude a manter o projeto no ar.
0737160d-e98f-4a65-8392-5dba70e7ff3eNo artigo anterior sobre microserviços, construímos um serviço de usuários seguindo Clean Architecture e DDD. Agora, vamos implementar um API Gateway com Kong para gerenciar a comunicação entre clientes e nossos microserviços.
O que é um API Gateway?
Um API Gateway é o ponto de entrada único para todas as requisições de clientes aos seus microserviços. Ele atua como um proxy reverso que roteia requisições, agrega respostas e fornece 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 que Kong?
Kong é um dos API Gateways mais populares e robustos do mercado:
Benefícios
| Característica | Descrição |
|---|---|
| Alta Performance | Construído em Nginx/OpenResty, suporta milhões de requests/segundo |
| Extensível | 100+ plugins oficiais e suporte a plugins customizados (Lua, Go, JavaScript) |
| Cloud Native | Integração nativa com Kubernetes, Helm charts oficiais |
| Open Source | Versão gratuita com todas funcionalidades essenciais |
| DB-less Mode | Pode rodar sem banco de dados, usando apenas configuração declarativa |
| Multi-protocol | HTTP, gRPC, WebSocket, TCP/UDP |
Kong vs Alternativas
| Gateway | Pontos Fortes | Pontos Fracos |
|---|---|---|
| Kong | Performance, extensibilidade, comunidade | Curva de aprendizado |
| AWS API Gateway | Integração AWS, serverless | Vendor lock-in, custo |
| Traefik | Simples, auto-discovery | Menos plugins |
| NGINX | Performance | Requer mais configuração manual |
| Envoy | Service mesh, observabilidade | Complexidade |
Arquitetura do 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) │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Conceitos Fundamentais
- Services: Representam seus microserviços upstream
- Routes: Definem como as requisições chegam aos services
- Consumers: Representam usuários ou aplicações que consomem suas APIs
- Plugins: Adicionam funcionalidades (auth, rate limiting, logging, etc.)
- Upstreams: Definem load balancing e health checks
Estrutura do Projeto
kong-gateway/
├── docker/
│ ├── docker-compose.yml
│ ├── docker-compose.dev.yml
│ └── docker-compose.prod.yml
│
├── kong/
│ ├── kong.yml # Configuração declarativa
│ ├── kong.conf # Configuração do Kong
│ │
│ ├── plugins/ # Plugins customizados
│ │ └── custom-auth/
│ │ ├── handler.lua
│ │ └── schema.lua
│ │
│ └── templates/ # Templates de configuração
│ └── nginx.conf
│
├── config/
│ ├── services/ # Definição dos services
│ │ ├── user-service.yml
│ │ ├── order-service.yml
│ │ └── product-service.yml
│ │
│ ├── routes/ # Definição das routes
│ │ ├── user-routes.yml
│ │ ├── order-routes.yml
│ │ └── product-routes.yml
│ │
│ ├── plugins/ # Configuração de plugins
│ │ ├── global-plugins.yml
│ │ ├── auth-plugins.yml
│ │ └── rate-limiting.yml
│ │
│ └── consumers/ # Definição de consumers
│ ├── mobile-app.yml
│ ├── web-app.yml
│ └── partners.yml
│
├── scripts/
│ ├── setup.sh # Script de setup inicial
│ ├── deploy.sh # Script de deploy
│ ├── backup.sh # Backup de configurações
│ └── health-check.sh # Health check dos services
│
├── 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
Instalação e Configuração
Docker Compose (Desenvolvimento)
# 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 KONG_LOG_LEVEL: info KONG_PLUGINS: bundled,custom-auth ports: - "8000:8000" # Proxy HTTP - "8443:8443" # Proxy HTTPS - "8001:8001" # Admin API HTTP - "8444:8444" # Admin API HTTPS healthcheck: test: ["CMD", "kong", "health"] interval: 10s timeout: 10s retries: 10 networks: - kong-net restart: unless-stopped konga: image: pantsel/konga:latest container_name: konga depends_on: - kong environment: NODE_ENV: production TOKEN_SECRET: your-secret-token ports: - "1337:1337" networks: - kong-net volumes: kong_data: networks: kong-net: driver: bridgeConfiguração Declarativa (DB-less)
# kong/kong.yml_format_version: "3.0"_transform: true # ===========================================# SERVICES# ===========================================services: # User Service - name: user-service url: http://user-service:3000 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 tags: - internal - users # Order Service - name: order-service url: http://order-service:3001 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 tags: - internal - orders # Product Service - name: product-service url: http://product-service:3002 connect_timeout: 5000 write_timeout: 60000 read_timeout: 60000 retries: 3 tags: - internal - products # ===========================================# ROUTES# ===========================================routes: # User Routes - name: user-api service: user-service paths: - /api/v1/users methods: - GET - POST - PUT - DELETE - PATCH strip_path: false preserve_host: true tags: - public - name: user-auth service: user-service paths: - /api/v1/auth methods: - POST strip_path: false tags: - public - auth # Order Routes - name: order-api service: order-service paths: - /api/v1/orders methods: - GET - POST - PUT - DELETE strip_path: false preserve_host: true tags: - public # Product Routes - name: product-api service: product-service paths: - /api/v1/products methods: - GET - POST - PUT - DELETE strip_path: false preserve_host: true tags: - public # ===========================================# UPSTREAMS (Load Balancing)# ===========================================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 passive: healthy: successes: 2 unhealthy: http_failures: 3 targets: - target: user-service-1:3000 weight: 100 - target: user-service-2:3000 weight: 100 - target: user-service-3:3000 weight: 100 # ===========================================# CONSUMERS# ===========================================consumers: - username: mobile-app custom_id: mobile-app-001 tags: - mobile - external - username: web-app custom_id: web-app-001 tags: - web - internal - username: partner-api custom_id: partner-001 tags: - partner - external # ===========================================# PLUGINS (Global)# ===========================================plugins: # Correlation ID para tracing - name: correlation-id config: header_name: X-Correlation-ID generator: uuid echo_downstream: true # Logging - name: file-log config: path: /var/log/kong/requests.log reopen: true # CORS - name: cors config: origins: - "https://app.example.com" - "https://admin.example.com" methods: - GET - POST - PUT - DELETE - PATCH - OPTIONS headers: - Accept - Authorization - Content-Type - X-Correlation-ID exposed_headers: - X-Correlation-ID credentials: true max_age: 3600 # Response Transformer - name: response-transformer config: add: headers: - "X-Powered-By:Kong" - "X-Response-Time:${latency}"Implementação de Plugins
1. Autenticação JWT
# config/plugins/auth-plugins.ymlplugins: # JWT Authentication (Global para rotas protegidas) - name: jwt route: user-api config: key_claim_name: kid claims_to_verify: - exp header_names: - Authorization uri_param_names: - jwt cookie_names: [] maximum_expiration: 86400 run_on_preflight: true # API Key para partners - name: key-auth route: partner-api config: key_names: - X-API-Key - apikey key_in_header: true key_in_query: true key_in_body: false hide_credentials: trueConfigurando JWT no Kong
# Criar consumercurl -X POST http://localhost:8001/consumers \ -d "username=mobile-app" \ -d "custom_id=mobile-001" # Criar credencial JWT para o consumercurl -X POST http://localhost:8001/consumers/mobile-app/jwt \ -d "algorithm=RS256" \ -d "key=mobile-app-key" \ -d "rsa_public_key=@/path/to/public_key.pem"2. Rate Limiting Avançado
# config/plugins/rate-limiting.ymlplugins: # Rate Limiting Global - name: rate-limiting-advanced config: limit: - 1000 # requests window_size: - 60 # seconds window_type: sliding sync_rate: 10 strategy: redis redis: host: redis port: 6379 database: 0 timeout: 2000 hide_client_headers: false identifier: consumer header_name: X-Consumer-Username # Rate Limiting por Rota (mais restritivo para auth) - name: rate-limiting route: user-auth config: minute: 10 hour: 100 policy: redis redis_host: redis redis_port: 6379 fault_tolerant: true hide_client_headers: false # Rate Limiting por Consumer (Partner com limite maior) - name: rate-limiting consumer: partner-api config: minute: 5000 hour: 100000 policy: redis redis_host: redis3. Request/Response Transformation
# config/plugins/transformations.ymlplugins: # Request Transformer - name: request-transformer route: user-api config: add: headers: - "X-Gateway-Version:1.0" - "X-Request-Start:$(now)" querystring: - "gateway:kong" remove: headers: - "X-Internal-Header" rename: headers: - "X-Old-Header:X-New-Header" # Response Transformer - name: response-transformer route: user-api config: add: headers: - "X-Response-Time:${latency}ms" - "X-Kong-Upstream-Status:${upstream_status}" remove: headers: - "X-Powered-By" - "Server"4. 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 local function set_circuit_state(conf, service_id, state) local cache_key = "circuit:" .. service_id kong.cache:set(cache_key, state, conf.state_ttl)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 state.failures = 0 set_circuit_state(conf, service_id, state) else return kong.response.exit(503, { message = "Service temporarily unavailable", circuit_state = OPEN, retry_after = conf.reset_timeout - (now - state.last_failure) }) end endend function CircuitBreakerHandler:response(conf) local service_id = kong.router.get_service().id local state = get_circuit_state(conf, service_id) local status = kong.response.get_status() if status >= 500 then state.failures = state.failures + 1 state.last_failure = ngx.now() if state.failures >= conf.failure_threshold then state.status = OPEN kong.log.warn("Circuit breaker OPEN for service: ", service_id) end else if state.status == HALF_OPEN then state.status = CLOSED kong.log.info("Circuit breaker CLOSED for service: ", service_id) end state.failures = 0 end set_circuit_state(conf, service_id, state)end return CircuitBreakerHandler-- kong/plugins/circuit-breaker/schema.lualocal typedefs = require "kong.db.schema.typedefs" return { name = "circuit-breaker", fields = { { consumer = typedefs.no_consumer }, { protocols = typedefs.protocols_http }, { config = { type = "record", fields = { { failure_threshold = { type = "integer", default = 5, gt = 0 }}, { reset_timeout = { type = "integer", default = 30, gt = 0 }}, { state_ttl = { type = "integer", default = 300, gt = 0 }}, }, }, }, },}Autenticação e Autorização
OAuth 2.0 / OpenID Connect
# config/plugins/oidc.ymlplugins: - name: openid-connect route: user-api config: issuer: https://auth.example.com/.well-known/openid-configuration client_id: kong-gateway client_secret: ${OIDC_CLIENT_SECRET} redirect_uri: https://api.example.com/callback scopes: - openid - profile - email auth_methods: - authorization_code - client_credentials consumer_claim: - sub consumer_by: - username - custom_id verify_claims: - exp - iss cache_ttl: 3600 cache_introspection: trueRBAC (Role-Based Access Control)
// Middleware de RBAC no seu microserviçointerface JWTPayload { sub: string; roles: string[]; permissions: string[]; exp: number;} export function requireRoles(...requiredRoles: string[]) { return (req: Request, res: Response, next: NextFunction) => { const token = req.headers['x-consumer-custom-id']; const roles = req.headers['x-consumer-roles']?.split(',') || []; const hasRole = requiredRoles.some(role => roles.includes(role)); if (!hasRole) { return res.status(403).json({ error: 'Forbidden', message: 'Insufficient permissions', required: requiredRoles, current: roles, }); } next(); };} // Uso no controllerapp.get('/api/v1/users', requireRoles('admin', 'user-manager'), userController.list);Observabilidade
Prometheus Metrics
# config/plugins/prometheus.ymlplugins: - name: prometheus config: per_consumer: true status_code_metrics: true latency_metrics: true bandwidth_metrics: true upstream_health_metrics: trueConfiguração do Prometheus
# monitoring/prometheus/prometheus.ymlglobal: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'kong' static_configs: - targets: ['kong:8001'] metrics_path: /metrics - job_name: 'kong-services' static_configs: - targets: - 'user-service:3000' - 'order-service:3001' - 'product-service:3002' metrics_path: /metrics alerting: alertmanagers: - static_configs: - targets: ['alertmanager:9093'] rule_files: - '/etc/prometheus/rules/*.yml'Alertas
# monitoring/prometheus/rules/kong-alerts.ymlgroups: - name: kong-alerts rules: - alert: KongHighLatency expr: histogram_quantile(0.95, rate(kong_latency_bucket[5m])) > 1000 for: 5m labels: severity: warning annotations: summary: "High latency detected on Kong" description: "95th percentile latency is above 1s" - 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 annotations: summary: "High error rate on Kong" description: "Error rate is above 5%" - alert: KongUpstreamDown expr: kong_upstream_target_health == 0 for: 1m labels: severity: critical annotations: summary: "Kong upstream target is down" description: "{{ $labels.upstream }} target {{ $labels.target }} is unhealthy" - alert: KongRateLimitExceeded expr: increase(kong_http_requests_total{code="429"}[5m]) > 100 for: 5m labels: severity: warning annotations: summary: "High rate limit exceeded count" description: "Many requests are being rate limited"Dashboard Grafana
{ "dashboard": { "title": "Kong API Gateway", "panels": [ { "title": "Requests per Second", "type": "graph", "targets": [ { "expr": "sum(rate(kong_http_requests_total[1m])) by (service)", "legendFormat": "{{service}}" } ] }, { "title": "Response Time (p95)", "type": "graph", "targets": [ { "expr": "histogram_quantile(0.95, sum(rate(kong_latency_bucket[5m])) by (le, service))", "legendFormat": "{{service}}" } ] }, { "title": "Error Rate", "type": "graph", "targets": [ { "expr": "sum(rate(kong_http_requests_total{code=~\"5..\"}[5m])) by (service) / sum(rate(kong_http_requests_total[5m])) by (service) * 100", "legendFormat": "{{service}}" } ] }, { "title": "Upstream Health", "type": "stat", "targets": [ { "expr": "kong_upstream_target_health", "legendFormat": "{{upstream}} - {{target}}" } ] } ] }}Distributed Tracing (Jaeger/Zipkin)
# config/plugins/tracing.ymlplugins: - name: zipkin config: http_endpoint: http://jaeger:9411/api/v2/spans sample_ratio: 1.0 include_credential: true traceid_byte_count: 16 header_type: preserve default_header_type: jaeger tags_header: X-B3-TagsDeploy em Kubernetes
Helm Chart
# Adicionar repositório oficialhelm repo add kong https://charts.konghq.comhelm repo update # Instalar Konghelm install kong kong/kong \ --namespace kong \ --create-namespace \ --values values.yamlValues.yaml Customizado
# k8s/helm/values.yamlimage: repository: kong tag: "3.5" env: database: "off" declarative_config: /kong/declarative/kong.yml # Plugins plugins: bundled,circuit-breaker # Logging proxy_access_log: /dev/stdout admin_access_log: /dev/stdout proxy_error_log: /dev/stderr admin_error_log: /dev/stderr log_level: info # Metrics status_listen: 0.0.0.0:8100 ingressController: enabled: true installCRDs: false proxy: enabled: true type: LoadBalancer http: enabled: true containerPort: 8000 servicePort: 80 tls: enabled: true containerPort: 8443 servicePort: 443 admin: enabled: true type: ClusterIP http: enabled: true containerPort: 8001 servicePort: 8001 status: enabled: true http: enabled: true containerPort: 8100 servicePort: 8100 secretVolumes: - kong-declarative-config resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2000m memory: 2Gi autoscaling: enabled: true minReplicas: 3 maxReplicas: 10 targetCPUUtilizationPercentage: 70 podDisruptionBudget: enabled: true minAvailable: 2 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app.kubernetes.io/name: kong topologyKey: kubernetes.io/hostnameKong Ingress Controller
# k8s/kong-ingress.yamlapiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: api-ingress annotations: konghq.com/strip-path: "false" konghq.com/plugins: rate-limiting,jwt-auth cert-manager.io/cluster-issuer: letsencrypt-prodspec: 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 - path: /api/v1/orders pathType: Prefix backend: service: name: order-service port: number: 3001 - path: /api/v1/products pathType: Prefix backend: service: name: product-service port: number: 3002KongPlugin CRD
# k8s/plugins/rate-limiting.yamlapiVersion: configuration.konghq.com/v1kind: KongPluginmetadata: name: rate-limiting namespace: kongconfig: minute: 1000 policy: redis redis_host: redis.kong.svc.cluster.local redis_port: 6379plugin: rate-limiting ---# k8s/plugins/jwt-auth.yamlapiVersion: configuration.konghq.com/v1kind: KongPluginmetadata: name: jwt-auth namespace: kongconfig: key_claim_name: kid claims_to_verify: - expplugin: jwtTestes
Testes de Integração
// tests/integration/kong.test.tsimport axios from 'axios'; const KONG_URL = process.env.KONG_URL || 'http://localhost:8000';const KONG_ADMIN = process.env.KONG_ADMIN || 'http://localhost:8001'; 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); expect(response.headers['x-kong-upstream-latency']).toBeDefined(); }); it('should return 404 for unknown routes', async () => { try { await axios.get(`${KONG_URL}/api/v1/unknown`); } catch (error: any) { expect(error.response.status).toBe(404); } }); }); describe('Authentication', () => { it('should reject requests without JWT', async () => { try { await axios.get(`${KONG_URL}/api/v1/users`, { headers: { 'Authorization': '' } }); } catch (error: any) { expect(error.response.status).toBe(401); } }); it('should accept requests with valid JWT', async () => { const token = await getValidJWT(); const response = await axios.get(`${KONG_URL}/api/v1/users`, { headers: { 'Authorization': `Bearer ${token}` } }); expect(response.status).toBe(200); }); }); 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); }); it('should include rate limit headers', async () => { const response = await axios.get(`${KONG_URL}/api/v1/users`); expect(response.headers['x-ratelimit-limit-minute']).toBeDefined(); expect(response.headers['x-ratelimit-remaining-minute']).toBeDefined(); }); }); describe('Health Checks', () => { it('should report healthy status', async () => { const response = await axios.get(`${KONG_ADMIN}/status`); expect(response.status).toBe(200); expect(response.data.database.reachable).toBe(true); }); });});Testes de Carga (k6)
// tests/load/k6-load-test.jsimport http from 'k6/http';import { check, sleep } from 'k6';import { Rate, Trend } from 'k6/metrics'; const errorRate = new Rate('errors');const latencyTrend = new Trend('latency'); export const options = { stages: [ { duration: '1m', target: 50 }, // Ramp-up { duration: '5m', target: 100 }, // Sustain { duration: '1m', target: 200 }, // Spike { duration: '2m', target: 100 }, // Recovery { duration: '1m', target: 0 }, // Ramp-down ], thresholds: { http_req_duration: ['p(95)<500'], errors: ['rate<0.01'], },}; const BASE_URL = __ENV.KONG_URL || 'http://localhost:8000';const TOKEN = __ENV.JWT_TOKEN; export default function () { const headers = { 'Authorization': `Bearer ${TOKEN}`, 'Content-Type': 'application/json', }; // GET Users const getUsers = http.get(`${BASE_URL}/api/v1/users`, { headers }); check(getUsers, { 'GET users status is 200': (r) => r.status === 200, 'GET users has data': (r) => r.json().data !== undefined, }); errorRate.add(getUsers.status !== 200); latencyTrend.add(getUsers.timings.duration); sleep(1); // POST User const payload = JSON.stringify({ email: `user-${Date.now()}@test.com`, password: 'Password123', name: 'Test User', }); const createUser = http.post(`${BASE_URL}/api/v1/users`, payload, { headers }); check(createUser, { 'POST user status is 201': (r) => r.status === 201, 'POST user has id': (r) => r.json().id !== undefined, }); errorRate.add(createUser.status !== 201); latencyTrend.add(createUser.timings.duration); sleep(1);}Checklist de Produção
Segurança
- TLS/SSL configurado em todas as portas
- Admin API protegida (não exposta publicamente)
- Secrets gerenciados via Vault/K8s Secrets
- Rate limiting habilitado
- CORS configurado corretamente
- Validação de input habilitada
- Headers de segurança configurados
Performance
- Connection pooling configurado
- Timeouts ajustados por serviço
- Cache habilitado onde apropriado
- Compressão gzip habilitada
- Keep-alive configurado
Resiliência
- Health checks configurados
- Circuit breaker implementado
- Retry policies configuradas
- Load balancing ativo
- Failover configurado
Observabilidade
- Métricas Prometheus expostas
- Logs estruturados
- Distributed tracing habilitado
- Alertas configurados
- Dashboards criados
Operacional
- Backup de configurações automatizado
- Runbook documentado
- Processo de rollback definido
- Disaster recovery testado
Conclusão
Um API Gateway bem implementado é fundamental para uma arquitetura de microserviços robusta. O Kong oferece uma base sólida com:
- Performance: Milhões de requests por segundo
- Flexibilidade: 100+ plugins e suporte a customização
- Observabilidade: Métricas, logs e tracing integrados
- Segurança: Autenticação, autorização e rate limiting
- Resiliência: Circuit breaker, retry e health checks
No próximo artigo, aprenda a implementar Mensageria com RabbitMQ para comunicação assíncrona entre microserviços.
Gostou do conteúdo? Sua contribuição ajuda a manter tudo online e gratuito!
0737160d-e98f-4a65-8392-5dba70e7ff3e