Lesson  in  Kubernetes 101

Gateway API

La evolución del Ingress: conoce la separación de roles de la Gateway API y publica tu aplicación con un HTTPRoute sobre un Gateway que el equipo de plataforma ya ha dejado preparado.

El Ingress de la lección anterior funciona, pero lleva años enseñando sus costuras. Todo lo que se sale de "host y path hacia Service" (timeouts, reescrituras, splits de tráfico) acaba en anotaciones propietarias de cada controller, así que un Ingress escrito para Traefik no sirve para nginx. Y hay un problema más profundo: es un único objeto que mezcla decisiones de infraestructura (puertos, TLS, dominios) con decisiones de aplicación (mis rutas), dos responsabilidades de equipos distintos.

La Gateway API es la respuesta oficial de Kubernetes, y su gran idea es separar los roles en tres recursos:

  • La GatewayClass la define el proveedor: qué tecnología implementa los Gateways (aquí, Traefik).
  • El Gateway lo gestiona el equipo de plataforma: qué puertos escuchan, con qué TLS, y quién puede engancharse.
  • El HTTPRoute lo escribe cada equipo de desarrollo: las rutas de su aplicación.

Esta lección respeta ese reparto: el equipo de plataforma (la tarea de inicialización del laboratorio) ya ha hecho su parte, y tú juegas el papel del desarrollador que publica su aplicación. Trabaja desde la pestaña dev-machine.

Paso 1: Inspecciona lo que plataforma te ha dejado

Antes de tocar nada, reconoce el terreno:

kubectl get gatewayclass
kubectl get gateway -A
kubectl describe gateway gateway -n plataforma

Fíjate en el -A y en el -n: el Gateway no está donde tú trabajas. Tú estás en tienda; el Gateway vive en plataforma, que es el Namespace del equipo que opera la entrada de tráfico. Esa separación no es un capricho de este laboratorio: es la razón de ser de esta API.

Del describe, dos cosas: la condición Programmed: True (el Gateway no es solo un objeto, hay un proxy real detrás) y la sección Listeners. Este es el Gateway que te han preparado:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: plataforma
spec:
  gatewayClassName: traefik
  listeners:
  - name: http
    protocol: HTTP
    port: 8000
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            expose: "true"

El YAML del Gateway, explicado con preguntas y respuestas

No lo has escrito tú, pero te conviene saber leerlo: es el contrato que plataforma te ofrece.

¿Otro grupo de API nuevo?

Sí, gateway.networking.k8s.io/v1, y con una particularidad: estos recursos no vienen de serie en Kubernetes, se instalan como CRDs (definiciones de recursos personalizados). Por eso la inicialización de esta lección los instaló primero. Es el mecanismo estándar con el que Kubernetes se extiende.

¿Qué papel juega gatewayClassName?

El mismo patrón que ya viste con las StorageClasses: elige la implementación. Aquí traefik, porque hemos activado el soporte de Gateway API del Traefik que k3s trae de serie.

¿Por qué el listener declara el puerto 8000 si luego llamaremos al 80?

Porque el listener se declara contra el puerto interno del entrypoint web de Traefik en k3s (8000), que el clúster publica hacia fuera como 80. Es un detalle de esta implementación concreta; lo importante es el concepto: el Gateway declara puertos de escucha, no los inventa.

¿Qué controla allowedRoutes?

La política de admisión del listener: qué rutas pueden engancharse a él, y es la mitad del apretón de manos entre plataforma y desarrollo. Hay tres valores. Same solo admite rutas del mismo Namespace, que en este montaje no admitiría ninguna porque nadie despliega aplicaciones en plataforma. All abre la puerta a todo el clúster. Y Selector, el de aquí, admite los Namespaces que lleven una etiqueta concreta.

¿Y quién pone esa etiqueta?

Plataforma, no tú. Compruébalo:

kubectl get ns tienda --show-labels

Ahí está el expose=true. Ese es el contrato entero en una etiqueta: plataforma decide qué Namespaces pueden publicar tráfico, y a partir de ahí cada equipo gestiona sus propias rutas sin pedir permiso ni tocar nada de plataforma. Con un Ingress esto no se podía expresar: cualquiera que supiera el nombre de la IngressClass publicaba lo que quisiera.

Paso 2: Tu aplicación

Lo de siempre, y ya sin guía: crea un Deployment web (1 réplica de ghcr.io/iximiuz/labs/nginx:alpine, etiqueta app: web, puerto 80) y un Service ClusterIP web que lo exponga en el puerto 80. Van en tienda, que es donde ya te deja el contexto: no hace falta que escribas -n.

Paso 3: El HTTPRoute, tu parte del contrato

Crea el archivo httproute.yaml:

cat << 'EOF' > httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tienda-route
spec:
  parentRefs:
  - name: gateway
    namespace: plataforma
  hostnames:
  - tienda.local
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: web
      port: 80
EOF

El YAML, explicado con preguntas y respuestas

¿Qué es parentRefs?

El enganche: esta ruta pide adjuntarse al Gateway gateway. Es la otra mitad del apretón de manos: tú solicitas, y el Gateway acepta o rechaza según sus allowedRoutes. El resultado queda escrito en el status de la ruta, no en el aire.

¿Por qué lleva namespace: plataforma?

Porque sin él, parentRefs busca el Gateway en el Namespace de la propia ruta, o sea en tienda, donde no hay ninguno. Quítalo y aplica: la ruta se crea igual, pero su status dirá que no ha encontrado padre. Es un fallo silencioso muy típico al empezar con Gateway API, y se diagnostica siempre en el mismo sitio, el status de la ruta.

Un detalle que sorprende: ¿no hace falta un ReferenceGrant para cruzar de Namespace?

No para esto. El ReferenceGrant hace falta cuando el que cruza es un backendRef, es decir, cuando una ruta quiere mandar tráfico a un Service de otro Namespace, y ahí sí tiene que autorizarlo el dueño del destino. Para engancharse a un Gateway ajeno la autorización ya está expresada en allowedRoutes, y por eso basta con la etiqueta.

¿En qué se diferencia una regla de las del Ingress?

En estructura y en potencia. Cada regla tiene matches (condiciones) y backendRefs (destinos), ambos en plural. Los matches pueden combinar path, cabeceras, método y query params, todo tipado en el spec, sin anotaciones propietarias.

¿Para qué querría varios backendRefs?

Para repartir tráfico con pesos: dos backends con weight: 90 y weight: 10 son un despliegue canary declarado en cinco líneas, algo que en Ingress requería anotaciones específicas de cada controller. No lo usamos aquí, pero es el ejemplo perfecto de por qué existe esta API.

¿PathPrefix es lo mismo que el pathType: Prefix del Ingress?

La misma idea con nombre propio del nuevo esquema. La familiaridad no es casual: la Gateway API se diseñó para que la migración mental desde Ingress fuera directa.

Aplícalo y mira algo que el Ingress nunca te dio, un status con opinión:

kubectl apply -f httproute.yaml
kubectl describe httproute tienda-route
kubectl get httproute tienda-route -o jsonpath='{.status.parents[0].conditions}' | jq

Busca la condición Accepted: True en la sección Status. El Gateway ha revisado tu solicitud y la ha admitido.

Paso 4: La prueba

Igual que con el Ingress, simula el DNS con la cabecera Host:

curl -H "Host: tienda.local" http://cplane-01/

La página de nginx, servida esta vez por la cadena Gateway, HTTPRoute, Service, Pod.

La pestaña tienda.local hace lo mismo desde un navegador: mismo puerto 80 de cplane-01, con la cabecera Host: tienda.local puesta por la plataforma. Fíjate en que el curl y la pestaña atraviesan la misma cadena: el Gateway del namespace plataforma y tu HTTPRoute del namespace tienda.

Note

💡 ¿Debo abandonar el Ingress ya? No hay prisa: el Ingress está congelado pero soportado, y seguirá años en producción. La regla práctica: proyectos nuevos con necesidades de enrutado serias, en Gateway API; lo existente que funciona, sin tocar. Saber leer ambos es lo que te hace útil hoy.

Resumen

  • La Gateway API separa lo que el Ingress mezclaba: GatewayClass (proveedor), Gateway (plataforma) y HTTPRoute (desarrollo).
  • Las capacidades avanzadas (matches ricos, pesos, cabeceras) son parte del esquema, no anotaciones propietarias.
  • Las rutas se adjuntan a Gateways con parentRefs, y el resultado del apretón de manos queda auditado en el status.
  • Los recursos llegan como CRDs: acabas de ver el mecanismo de extensión de Kubernetes en acción, y volverá a aparecerte en cuanto toques operadores.
Previous lesson
Ingress
Next lesson
NetworkPolicy