<!-- Canonical: https://lucioduran.com/es/blog/kubernetes-gateway-api-envoy-cilium
Language: es
Content-SHA256: e6037e09215fc475f23181be4a9277222d60ca124cdd92834ec7b8b5934f1b11
-->

Infrastructure

# Gateway API de Kubernetes: Reemplazando Ingress con Envoy Gateway y Cilium

2026-02-066 min lectura

Lucio Durán
Engineering Manager & AI Solutions Architect

También disponible en: [English](<https://lucioduran.com/blog/kubernetes-gateway-api-envoy-cilium>)

## Limitaciones del recurso Ingress

El recurso Ingress era intencionalmente mínimo. Manejaba ruteo HTTP (host + path -\> backend) y terminación TLS. Todo lo demás, rate limiting, autenticación, rewriting, CORS, soporte WebSocket, gRPC, ruteo TCP/UDP, canary deployments, se empujaba a annotations específicas del controller.

```yaml
# Un Ingress de producción típico con annotations específicas del controller
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: api-gateway
 annotations:
 # Específico de nginx - no funciona con traefik ni otro controller
 nginx.ingress.kubernetes.io/ssl-redirect: "true"
 nginx.ingress.kubernetes.io/proxy-body-size: "50m"
 nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
 nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
 nginx.ingress.kubernetes.io/rate-limit-rps: "100"
 nginx.ingress.kubernetes.io/configuration-snippet: |
 more_set_headers "X-Request-ID: $req_id";
 if ($http_upgrade = "websocket") {
 proxy_pass http://upstream;
 }
spec:
 tls:
 - hosts:
 - api.example.com
 secretName: api-tls
 rules:
 - host: api.example.com
 http:
 paths:
 - path: /v1
 pathType: Prefix
 backend:
 service:
 name: api-v1
 port:
 number: 8080
```

Esto es un desastre. Las annotations son strings no validados. El ` configuration-snippet ` es config nginx cruda que se inyecta tal cual, una vulnerabilidad de seguridad si cualquier usuario no confiable puede setear annotations (CVE-2021-25742 fue exactamente esto). Y nada es portable entre controllers.

## Gateway API: El Modelo de Tres Recursos

La Gateway API reemplaza el recurso Ingress con un modelo de tres capas que mapea a roles organizacionales:

```
┌─────────────────────────────────────────────────┐
│ GatewayClass (Admin del cluster) │
│ "Qué implementación de controller usar" │
│ Se crea una vez por cluster │
├─────────────────────────────────────────────────┤
│ Gateway (Equipo de plataforma / SRE) │
│ "Dónde escuchar, config TLS, rutas permitidas" │
│ Uno por punto de entrada (externo, interno, etc)│
├─────────────────────────────────────────────────┤
│ HTTPRoute / TLSRoute / GRPCRoute (Equipo app) │
│ "Cómo rutear tráfico a mi servicio" │
│ Uno por servicio o grupo de servicios │
└─────────────────────────────────────────────────┘
```

Esta separación es la característica más destacada. El equipo de plataforma controla el Gateway, puertos, certificados TLS, namespaces permitidos. Los equipos de app crean Routes en sus propios namespaces. Se acabó el "necesito cluster-admin para agregar una annotation a mi Ingress."

Acá está el equivalente en Gateway API del horror nginx-ingress de arriba:

```yaml
# GatewayClass - el admin del cluster configura esto una vez
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
 name: envoy
spec:
 controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
# Gateway - el equipo de plataforma maneja esto
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
 name: external
 namespace: gateway-infra
spec:
 gatewayClassName: envoy
 listeners:
 - name: https
 port: 443
 protocol: HTTPS
 tls:
 mode: Terminate
 certificateRefs:
 - name: wildcard-tls
 namespace: cert-manager
 allowedRoutes:
 namespaces:
 from: Selector
 selector:
 matchLabels:
 gateway-access: "true"
---
# HTTPRoute - el equipo de app crea esto en su namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
 name: api-v1
 namespace: api-team
spec:
 parentRefs:
 - name: external
 namespace: gateway-infra
 hostnames:
 - "api.example.com"
 rules:
 - matches:
 - path:
 type: PathPrefix
 value: /v1
 backendRefs:
 - name: api-v1
 port: 8080
```

Cada campo es validado por el API server de Kubernetes. Los typos se rechazan al hacer apply, no se ignoran silenciosamente. La ruta referencia su Gateway padre explícitamente. Y el mismo HTTPRoute funciona con Envoy Gateway, Cilium, Istio o cualquier implementación conformante.

## Traffic Splitting: Canary Sin Tooling

Acá es donde la Gateway API provee valor inmediato. Usar Flagger + nginx-ingress para canary deployments lo que significaba correr un controller custom que manipulaba annotations para mover tráfico. Con Gateway API, el traffic splitting es nativo:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
 name: api-canary
 namespace: api-team
spec:
 parentRefs:
 - name: external
 namespace: gateway-infra
 hostnames:
 - "api.example.com"
 rules:
 - matches:
 - path:
 type: PathPrefix
 value: /v2
 backendRefs:
 - name: api-v2-stable
 port: 8080
 weight: 95
 - name: api-v2-canary
 port: 8080
 weight: 5
```

Cinco por ciento del tráfico va al canary. Ajustás los pese es y reaplicás. Sin controllers custom, sin gimnasia de annotations.

## TLS Passthrough: Lo que Ingress Nunca Hizo Bien

TLS passthrough, reenviar tráfico encriptado sin terminar TLS en el gateway, fue un dolor de cabeza constante con Ingress. Gateway API lo maneja con TLSRoute y modos de listener del Gateway:

```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
 name: external
 namespace: gateway-infra
spec:
 gatewayClassName: envoy
 listeners:
 - name: https-terminate
 port: 443
 protocol: HTTPS
 tls:
 mode: Terminate
 certificateRefs:
 - name: wildcard-tls
 allowedRoutes:
 kinds:
 - kind: HTTPRoute
 - name: tls-passthrough
 port: 443
 protocol: TLS
 tls:
 mode: Passthrough
 hostname: "vault.example.com"
 allowedRoutes:
 kinds:
 - kind: TLSRoute
```

Los dos listeners comparten el puerto 443. El Gateway inspecciona el SNI (Server Name Indication) en el ClientHello de TLS para decidir si terminar o pasar directo. Se maneja a nivel de protocolo, sin hacks de annotations.

## Cilium: Service Mesh Sin el Impuesto del Sidecar

Para tráfico east-west (servicio a servicio), Cilium con Gateway API es una opción efectiva. El approach basado en eBPF de Cilium significa que no hay sidecars, la lógica de networking corre en el kernel:

La diferencia de rendimiento entre Cilium (eBPF) y meshes basados en sidecar (Istio con sidecars Envoy) es medible. En un servicio sensible a latencia manejando 50K RPS:

| Métrica | Sin mesh | Istio sidecar | Cilium eBPF |
| --- | --- | --- | --- |
| Latencia P50 | 2.1ms | 3.4ms | 2.3ms |
| Latencia P99 | 8.7ms | 14.2ms | 9.1ms |
| Memoria por pod | base | +50MB (sidecar) | +0MB |
| CPU por pod | base | +0.1 core (sidecar) | +~0 |

El overhead del sidecar es 50MB de RAM y 0.1 core de CPU por pod. En 200 servicios con 3 réplicas cada uno, son 30GB de RAM y 60 cores de CPU solo para el mesh. Cilium elimina esto completamente.

## La Migración: 200 Servicios en 6 Semanas

La migración incremental funciona bien. El insight clave: Gateway API e Ingress pueden coexistir en el mismo cluster porque usan recurse es distintos.

Semana 1-2: Deploy de Envoy Gateway junto a nginx-ingress. Crear GatewayClass y Gateway. Migrar 5 servicios no críticos.

Semana 3-4: Migrar todos los servicios API stateless. Validar con tráfico sintético antes de cambiar DNS.

Semana 5: Migrar servicios con requerimientos de WebSocket y gRPC. Estos fueron más fáciles con Gateway API porque HTTPRoute soporta nativamente upgrades WebSocket y existe GRPCRoute.

Semana 6: Migrar servicios restantes, decomisionar nginx-ingress.

Un hallazgo notable: se encontraron 23 recurse es Ingress con annotations rotas que nadie había notado. Typos, nombres de annotations deprecadas, annotations para el controller equivocado. Todas silenciosamente sin hacer nada. Gateway API las habría rechazado al momento de crearlas.

## Lo Que le Falta a Gateway API

Persisten algunos gaps:

**Rate limiting no está estandarizado.** Cada implementación tiene sus propios CRDs. La propuesta GEP-1731 para policy attachment sigue evolucionando.

**Autenticación/autorización a nivel gateway** es específica de implementación. No hay un filtro HTTPRoute estándar para validación JWT u OAuth2.

**Ruteo TCP/UDP** funciona (TCPRoute, UDPRoute) pero sigue en el canal experimental.

A pesar de estos gaps, Gateway API representa la dirección correcta. El modelo de seguridad role-based, la configuración tipada, la portabilidad entre implementaciones y las features nativas de traffic management la hacen un upgrade claro del approach de Ingress que se usó durante siete años.

Para clusters que todavía corren Ingress con configuraciones pesadas en annotations, planear una migración es una inversión que vale la pena.

## Preguntas frecuentes

### ¿La Gateway API está lista para producción?

Sí. Gateway API llegó a GA (v1.0) en octubre 2023 y v1.2 es la actual a principios de 2026. Envoy Gateway, Cilium, Istio, Traefik y Kong tienen implementaciones production-grade. El spec es estable para features core (Gateway, HTTPRoute, TLSRoute).

### ¿Debería migrar de nginx-ingress a Gateway API?

Si se está manejando más de 20-30 servicios, sí. Solo el modelo role-based (el equipo de plataforma maneja Gateways, los equipos de app manejan Routes) justifica la migración. Si teners 3-5 servicios y nginx-ingress funciona, el costo de migración probablemente no vale la pena todavía.

### ¿Envoy Gateway o Cilium para Gateway API?

Envoy Gateway si se necesita traffic management avanzado (rate limiting, autenticación, circuit breaking) y no se desea un service mesh completo. Cilium si ya lo usás para CNI/networking y se desea Gateway API integrada con observabilidad basada en eBPF y network policies.

## Tips

1. **Tip:** Al migrar de Ingress a Gateway API, no convertir todos los recursos de una vez. Utilizar ` parentRefs ` en HTTPRoute para vincular rutas a Gateways específicos, es posible ejecutar Ingress y Gateway API simultáneamente durante la migración.
2. **Tip:** Para TLS passthrough (no terminación), utilizar ` TLSRoute ` con ` mode: Passthrough ` en el listener del Gateway. Este es el aspecto que las annotations de Ingress nunca manejaron de forma limpia entre controllers.
3. **Tip:** Configurar pesos en ` backendRefs ` para traffic splitting: ` weight: 90 ` y ` weight: 10 ` proporciona un canary 90/10 sin tooling externo. El controller del Gateway maneja el ruteo ponderado nativamente.
4. **Tip:** Con Cilium Gateway API, habilitar ` hubble ` para observabilidad L7. Se obtienen histogramas de latencia por ruta y tasas de error sin desplegar un stack de observabilidad separado.

- kubernetes
- gateway-api
- envoy
- cilium
- ingress
- service-mesh
- httproute
- tls
- traffic-splitting
- infraestructura

[Volver al Blog](<https://lucioduran.com/es/blog>)
