TL;DR — Resumen Rápido

Guía completa de Envoy Proxy para service mesh y edge proxy. Cubre xDS API, balanceo de carga, mTLS, observabilidad, circuit breaking y sidecar en Kubernetes.

Envoy Proxy es el plano de datos en el corazón de los service mesh modernos. Creado originalmente en Lyft para resolver la observabilidad y confiabilidad de microservicios a escala, Envoy es hoy el sidecar de facto para Istio, el edge proxy de muchos controladores de ingress y un proxy L3/L4/L7 de propósito general usado por Google, AWS y miles de empresas. Esta guía cubre la arquitectura de Envoy, configuración estática y dinámica, algoritmos de balanceo de carga, pipeline de observabilidad, gestión de TLS y filtros avanzados.

Requisitos Previos

  • Docker (para pruebas autónomas) o un clúster de Kubernetes.
  • Conocimiento básico de HTTP, TLS y conceptos de proxy inverso.
  • Familiaridad con la sintaxis de configuración YAML.
  • curl y opcionalmente jq para probar endpoints.

Arquitectura de Envoy

Envoy opera como un proxy de red fuera del proceso — se ejecuta junto a tu aplicación en lugar de como una biblioteca dentro de ella. Esto mantiene el proxy independiente del lenguaje y permite actualizaciones independientes.

Componentes principales:

  • Listeners — Puertos de red donde Envoy escucha (aquí llegan las conexiones downstream).
  • Cadenas de filtros — Lista ordenada de filtros de red y HTTP aplicados a cada conexión.
  • Clústeres — Grupos nombrados de endpoints upstream (tus servicios backend).
  • Endpoints — Pares IP:puerto individuales dentro de un clúster, descubiertos vía EDS o config estática.
  • Rutas — Reglas que mapean solicitudes entrantes a clústeres basadas en ruta, cabecera o parámetros de consulta.

Modelo de hilos: Envoy usa un hilo principal para gestión más un hilo trabajador por núcleo de CPU. Cada hilo trabajador gestiona conexiones de forma independiente usando I/O no bloqueante. No hay contención de bloqueos en el camino caliente — cada worker tiene su propio pool de conexiones.

Hot restart: Envoy soporta actualizaciones binarias sin tiempo de inactividad mediante un handshake en memoria compartida entre el proceso antiguo y el nuevo. El nuevo proceso toma el control de las conexiones existentes sin perder tráfico.


Configuración Estática (envoy.yaml)

La forma más rápida de comenzar es una configuración YAML estática con todos los recursos definidos en línea:

admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10000
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["*"]
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: service_backend
                            timeout: 15s
                            retry_policy:
                              retry_on: "5xx,reset,connect-failure"
                              num_retries: 3
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
    - name: service_backend
      connect_timeout: 0.5s
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: service_backend
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: backend-service
                      port_value: 8080
      health_checks:
        - timeout: 1s
          interval: 10s
          unhealthy_threshold: 2
          healthy_threshold: 2
          http_health_check:
            path: /health

El bloque admin expone la API de gestión de Envoy en el puerto 9901. Úsalo para consultar /stats, /clusters, /config_dump y /healthcheck/fail para pruebas de circuit-breaker.


Configuración Dinámica: La API xDS

Las configuraciones estáticas funcionan para despliegues simples pero se vuelven difíciles de manejar a escala. El protocolo xDS (x Discovery Service) de Envoy permite que un plano de control envíe cambios de configuración en tiempo de ejecución — sin recarga, sin reinicio.

Tipos de recursos xDS:

APIGestiona
LDS (Listener Discovery Service)Listeners y cadenas de filtros
RDS (Route Discovery Service)Hosts virtuales y tablas de rutas
CDS (Cluster Discovery Service)Definiciones de clústeres y políticas
EDS (Endpoint Discovery Service)Salud individual de endpoints IP:puerto
SDS (Secret Discovery Service)Certificados TLS y claves privadas

ADS (Aggregated Discovery Service): Combina todas las APIs xDS en un único stream gRPC bidireccional. Es el modo recomendado porque garantiza el orden — un nuevo clúster siempre se entrega antes que la ruta que lo referencia, evitando errores 503 temporales durante las actualizaciones.

Delta xDS: En lugar de enviar el estado completo en cada actualización, delta xDS envía solo los recursos añadidos, modificados o eliminados. Esencial para mallas grandes con miles de clústeres.


Algoritmos de Balanceo de Carga

Envoy soporta seis políticas de balanceo de carga seleccionables por clúster:

PolíticaMejor Para
ROUND_ROBINCapacidad uniforme del backend, elección predeterminada
LEAST_REQUESTDuración variable de solicitudes, evita backends sobreocupados
RING_HASHHash consistente — afinidad de caché, servicios con estado
RANDOMSimple, bajo overhead, resistente a endpoints lentos
MAGLEVHash consistente de Google — distribución más uniforme
CLUSTER_PROVIDEDDelega la decisión al tipo de clúster upstream

Observabilidad

Envoy es dogmático sobre la observabilidad — fue construido para hacer depurables los sistemas distribuidos. Tres pilares integrados:

Estadísticas: Envoy emite miles de contadores, indicadores e histogramas. Expónlos a Prometheus en el endpoint admin:

curl http://localhost:9901/stats/prometheus

Trazabilidad Distribuida: Envoy genera y propaga automáticamente cabeceras de contexto de traza para Jaeger, Zipkin y OpenTelemetry. Tu aplicación solo necesita reenviar estas cabeceras — Envoy maneja la creación de trazas.

Registro de Acceso: Logs de acceso JSON estructurado con todos los metadatos de la solicitud, incluyendo clúster upstream, duración, código de respuesta y bytes enviados.


TLS y mTLS con SDS

El Secret Discovery Service (SDS) de Envoy resuelve la distribución manual de certificados: los certificados se obtienen de un plano de control en tiempo de ejecución y se rotan sin reinicio del proceso.

Para TLS mutuo entre servicios, el campo match_subject_alt_names aplica la identidad SPIFFE — solo se aceptan conexiones de servicios con el URI SPIFFE esperado. Así es como Istio implementa redes de confianza cero: cada conexión pod a pod se autentica mutuamente mediante certificados de corta duración rotados por SPIRE.


Filtros Avanzados

Circuit Breaking: Previene fallos en cascada limitando solicitudes pendientes, reintentos y conexiones. Configura max_connections, max_pending_requests, max_requests y max_retries por clúster.

Detección de Outliers: Expulsa automáticamente hosts no saludables del pool de balanceo. Tras cinco respuestas 5xx consecutivas, el endpoint se expulsa durante 30 segundos. max_ejection_percent evita expulsar todos los hosts cuando el upstream degrada globalmente.

Inyección de Fallos: Inyecta latencia o errores en un porcentaje de solicitudes para pruebas de caos, configurable por ruta sin cambios en el código de la aplicación.

Autorización Externa: Delega decisiones de autorización a un servicio gRPC externo (OPA, Ory Keto). El filtro ext_authz envía cabeceras de solicitud al servicio de autorización antes de reenviar upstream.

Extensiones Wasm: Envoy soporta plugins de filtro WebAssembly para lógica de negocio personalizada en cualquier lenguaje que compile a Wasm (Go, Rust, C++). Los filtros Wasm se recargan en caliente sin actualizaciones binarias.


Envoy vs Otros Proxies

CaracterísticaEnvoyNginxHAProxyTraefikLinkerdMOSN
Config dinámicaAPI xDS (sin recarga)nginx -s reloadAPI en tiempo realAuto-descubre K8sxDS (limitado)API xDS
Service meshSí (Istio, Consul)NoNoNo (solo ingress)Sí (Linkerd2)
Protocolos L7HTTP/1.1, HTTP/2, gRPC, ThriftHTTP/1.1, HTTP/2HTTP/1.1, HTTP/2HTTP/1.1, HTTP/2HTTP/1.1, HTTP/2, gRPCHTTP/1.1, HTTP/2, Dubbo
ObservabilidadStats + tracing integradosBasado en módulosSocket de statsPlugin PrometheusSeñales doradas integradasStats integrados
mTLSSDS + SPIFFECerts manualesCerts manualesCerts manualesAutomáticoSDS
Filtros WasmNoNoNoNo

Ejemplo Práctico: Envoy como Proxy Frontal

Tienes tres microservicios (users, orders, products) detrás de Envoy como edge proxy, con tráfico dividido entre v1 y v2 del servicio de órdenes para un despliegue canary:

routes:
  - match:
      prefix: "/orders"
    route:
      weighted_clusters:
        clusters:
          - name: orders_v1
            weight: 90
          - name: orders_v2
            weight: 10
        total_weight: 100

Esta configuración de clúster ponderado envía el 10% del tráfico /orders al canary v2 sin cambios en el código de la aplicación.


Errores Comunes y Casos Límite

  • Sensibilidad a mayúsculas de cabeceras: Las cabeceras HTTP/2 son minúsculas por defecto. Envoy las normaliza — asegúrate de que tus servicios manejen content-type, authorization en minúsculas.
  • Timeouts upstream vs de ruta: connect_timeout del clúster (TCP) y timeout de la ruta (solicitud) son independientes. El timeout de ruta predeterminado es 15 segundos — establécelo explícitamente.
  • Presupuesto de reintentos: Sin límites en retry_on, los reintentos bajo carga pueden amplificar fallos. Combina siempre los reintentos con un circuit breaker.

Solución de Problemas

SíntomaCausa ProbableSolución
503 upstream_reset_before_response_startedUpstream cerró conexión antes de responderVerifica la ruta de health check; aumenta connect_timeout
404 de Envoy (no del upstream)Sin ruta coincidenteEjecuta /config_dump en el puerto admin; verifica el dominio del virtual host
Circuit breaker abierto en statsUpstream sobrecargadoAumenta max_pending_requests o escala el upstream
Fallo de handshake mTLSDiscrepancia en SAN del certificadoVerifica que match_subject_alt_names coincida con el URI SPIFFE real
Alta latencia P99Inanición de hilosAumenta el conteo de worker threads con concurrency en el bootstrap

Resumen

  • La API xDS habilita configuración completamente dinámica sin reinicios — clústeres, rutas, listeners y certificados se actualizan en vivo.
  • El balanceo de carga ofrece seis algoritmos incluyendo Ring Hash para afinidad de caché y Least Request para cargas de trabajo heterogéneas.
  • La observabilidad integrada proporciona stats Prometheus, cabeceras de trazado distribuido y logs de acceso JSON estructurado.
  • mTLS vía SDS + SPIFFE entrega redes de confianza cero con certificados de corta duración rotados automáticamente.
  • Los filtros avanzados hacen a Envoy extensible sin tocar el código de la aplicación.

Artículos Relacionados