Expón Services con el soporte de Gateway API de Cilium
GatewayClass, Gateway y HTTPRoute: enrutamiento por host, coincidencia de rutas, reescrituras de URL y TLS, sin Pods de gateway separados.
Kubernetes Gateway API es el sucesor estandarizado de Ingress, y Cilium lo implementa directamente usando su propio plano de datos eBPF más un Envoy embebido para el procesamiento de capa 7. Esta guía cubre los recursos principales, GatewayClass, Gateway, HTTPRoute, y los patrones de enrutamiento construidos con ellos, asumiendo que Cilium ya está instalado con Gateway API habilitado (consulta la guía anterior).
GatewayClass: declarar Cilium como controlador disponible
Un GatewayClass le dice al clúster “este controlador está disponible para que lo usen los Gateways”:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
Si estableciste gatewayAPI.gatewayClass.create: false durante la instalación (como recomienda la guía anterior), este es el recurso que creas tú mismo para cubrir ese hueco.
Personaliza la clase con CiliumGatewayClassConfig
Cilium ofrece su propio CRD, CiliumGatewayClassConfig, para los ajustes que deben aplicarse a todos los Gateways que usen una clase dada, con más frecuencia el tipo de Service de Kubernetes a través del cual se expone el Gateway:
apiVersion: cilium.io/v2alpha1
kind: CiliumGatewayClassConfig
metadata:
name: gateway-api-config
namespace: default
spec:
service:
type: NodePort
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
parametersRef:
group: cilium.io
kind: CiliumGatewayClassConfig
name: gateway-api-config
namespace: default
NodePort aquí es específicamente una concesión para clústeres kind, que se explica más abajo; en un clúster con un balanceador de carga real en la nube disponible, LoadBalancer es la opción más típica, y guías posteriores de esta serie sobre el anuncio de rutas BGP cubren cómo obtener una dirección enrutable sin el balanceador de carga de un proveedor de nube.
Crea un Gateway
Un Gateway es la configuración real de los listeners, que hace referencia a la clase anterior:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: demo-gateway
namespace: default
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- name: demo-tls-secret
Sin Pods de gateway: aquí es donde Cilium se diferencia
Con la mayoría de las implementaciones de Gateway API, crear un Gateway produce un Deployment y Pods dedicados para esa instancia de gateway. Con Cilium no ocurre así: el tráfico se intercepta mediante eBPF a nivel de nodo y se enruta según la configuración del Gateway, y solo aparece un Service de Kubernetes, sin Pods dedicados al Gateway en sí.
kubectl get gateway demo-gateway
kubectl get service -l gateway.networking.k8s.io/gateway-name=demo-gateway
En un clúster kind en concreto, un Service NodePort recibe por defecto un puerto aleatorio, no los puertos que realmente quieres (30080/30443 de la configuración anterior del clúster kind). Parchéalo explícitamente:
kubectl patch service <gateway-service-name> --type='json' -p='[
{"op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080},
{"op": "replace", "path": "/spec/ports/1/nodePort", "value": 30443}
]'
Este paso de parcheo es únicamente un workaround de clústeres kind por su falta de un balanceador de carga real, no una limitación general de Cilium. En un clúster con una implementación real de LoadBalancer en la nube, o con los anuncios L2 de Cilium o el anuncio de rutas BGP (una guía posterior de esta serie), el Service del Gateway recibe una dirección enrutable sin parcheo manual.
Enruta por nombre de host
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: python-route
namespace: default
spec:
parentRefs:
- name: demo-gateway
hostnames:
- "python.example.com"
rules:
- backendRefs:
- name: python-service
port: 5000
parentRefs vincula esta ruta al Gateway (deben estar en el mismo namespace, o la ruta necesita una política explícita de referencia entre namespaces). Cualquier petición que llegue con el encabezado Host python.example.com se envía a python-service.
Enruta por ruta: coincidencia exacta vs. por prefijo
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: python-service
port: 5000
Exact coincide solo con esa ruta literal; una petición a /status no coincidiría con una regla limitada a /. Para cualquier cosa más allá de una sola ruta fija, PathPrefix coincide con el prefijo dado y reenvía el resto de la ruta sin cambios:
rules:
- matches:
- path:
type: PathPrefix
value: /
La distinción importa en la práctica: una API con varios endpoints detrás de una sola ruta necesita PathPrefix, no Exact, o cada endpoint más allá de la ruta literal coincidente devuelve un route-not-found en lugar de llegar al backend.
Reescrituras de URL: una ruta externa limpia, otra distinta internamente
Un patrón habitual es exponer varios servicios backend bajo un único nombre de host consolidado con un esquema de rutas ordenado, mientras cada backend mantiene sus propias rutas internas sin conocer ese prefijo externo:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: python-route
namespace: default
spec:
parentRefs:
- name: demo-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/python
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: python-service
port: 5000
Una petición a example.com/api/python/status coincide con el prefijo /api/python, se reescribe a /status antes de llegar a python-service, de modo que el backend nunca necesita conocer el prefijo /api/python que ve el exterior. Define una ruta paralela para cada servicio backend (/api/go hacia un servicio en Go, y así sucesivamente) para construir un único gateway de API consolidado a partir de varios backends desarrollados de forma independiente, cada uno sin conocer la estructura de rutas que el gateway presenta externamente.
TLS: dos cosas deben coincidir
Servir tráfico HTTPS requiere configurar dos piezas de forma coherente:
- El listener HTTPS del Gateway (mostrado arriba) referencia un Secret TLS y establece
mode: Terminate. - Cada
HTTPRouteque deba aceptar tráfico HTTPS necesita que su entradaparentRefsapunte realmente a ese listener HTTPS por nombre, no solo al Gateway en conjunto:
parentRefs:
- name: demo-gateway
sectionName: https
Sin sectionName apuntando específicamente al listener HTTPS, una ruta se vincula al listener (o listeners) que por defecto encajen con sus criterios de coincidencia, que puede no incluir el que pretendías. Crea el Secret TLS antes de aplicar un Gateway que lo referencie:
kubectl create secret tls demo-tls-secret \
--cert=path/to/cert.pem \
--key=path/to/key.pem \
-n default
kubectl describe gateway demo-gateway es el primer lugar donde mirar si un listener no acepta tráfico como se espera; un Secret TLS ausente o mal formado es un motivo común por el que un listener aparece como no aceptado.
Guías populares
-
Cómo usa Cilium eBPF: identidad, políticas y sockets Qué ocurre realmente en el kernel cuando un Pod arranca, habla con otro Pod o recibe una decisión de política sobre un paquete, y por qué es rápido. -
Prepara un clúster para Cilium: desactiva primero la CNI predeterminada Cilium reemplaza por completo el networking de tu clúster, lo que significa que el orden de las operaciones importa más que con la mayoría de los complementos. -
Escribe network policies: de reglas L3/L4 a L7 Kubernetes parte de que todo Pod puede alcanzar a cualquier otro Pod; CiliumNetworkPolicy es la forma de acotarlo, hasta el método HTTP si lo necesitas.