Una mirada rápida a la API de Kubernetes Gateway

Nicolas Fränkel

Nicolas Fränkel

September 7, 2022

Ecosystem

En uno de mis posts recientes del blog, describí varias formas de acceder a los pods de Kubernetes. Se puede acceder a un pod a través de su IP, pero los pods son naturalmente transitorios. La forma nominal es configurar un Service: su IP es estable, y el trabajo de Kubernetes es mantener actualizado el mapeo entre un Service y los pods subyacentes. Hay diferentes tipos de servicios disponibles: solo internos, NodePort para permitir finalmente el acceso desde fuera del clúster, y LoadBalancer que depende de un componente de terceros, generalmente un proveedor de la nube. Finalmente, mencioné el objeto Ingress, que también permite el enrutamiento.

Deliberadamente dejé fuera al nuevo en el bloque, la API Gateway. Este es el tema de este post.

De Ingress a la API Gateway

El acceso externo a los pods de Kubernetes ha pasado por varios pasos evolutivos, por ejemplo, Ingress es la respuesta al problema de la falta de enrutamiento en LoadBalancer. El mayor problema de Ingress es su dependencia de objetos "propietarios". Como recordatorio, aquí está el fragmento para crear enrutamiento usando Apache APISIX:

apiVersion: apisix.apache.org/v2beta3 #1
kind: ApisixRoute #1
metadata:
  name: apisix-route
spec:
  http:
    - name: left
      match:
        paths:
          - "/left"
      backends:
        - serviceName: left
          servicePort: 80
    - name: right
      match:
        paths:
          - "/right"
      backends:
        - serviceName: right
          servicePort: 80
  1. Objetos propietarios

Los objetos propietarios son un problema al migrar. Aunque la migración de un proveedor a otro probablemente no sea común, debería ser lo más fluida posible. Al usar objetos propietarios, primero necesitas mapear del objeto antiguo a los nuevos. Es probable que no sea un mapeo uno a uno. Luego, necesitas traducir la especificación al nuevo modelo: es probable que sea un proyecto completo.

La idea detrás de la API Gateway es tener una separación clara entre los objetos estándar y la implementación propietaria.

La API Gateway

La API Gateway es un proyecto de código abierto gestionado por la comunidad SIG-NETWORK. Es una colección de recursos que modelan la red de servicios en Kubernetes. Estos recursos - GatewayClass, Gateway, HTTPRoute, TCPRoute, Service, etc - tienen como objetivo evolucionar la red de servicios de Kubernetes a través de interfaces expresivas, extensibles y orientadas a roles que son implementadas por muchos proveedores y tienen un amplio apoyo de la industria.

-- https://gateway-api.sigs.k8s.io

La definición anterior también menciona una preocupación organizativa: diferentes roles deberían gestionar un conjunto diferente de objetos.

Modelo de la API Gateway

Imagen de gateway-api.sigs.k8s.io

De hecho, las preocupaciones de un operador de clúster y un desarrollador son bastante diferentes. Es bastante similar a los servidores de aplicaciones Java EE de antaño, que ofrecían una especificación organizada en torno a roles: desarrolladores, implementadores y operadores. En mi opinión, la diferencia más significativa es que la especificación se centraba principalmente en la experiencia del desarrollador; el resto dependía de los implementadores. La API Gateway parece preocuparse por todas las personas.

Configurar el acceso a los pods a través de la API Gateway

Reemplacemos el Ingress que configuramos anteriormente con la API Gateway. Son necesarios varios pasos.

Instalar los nuevos CRDs de Gateway

k apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v0.5.0/standard-install.yaml

Instalar una implementación

Usaré Apache APISIX. Alternativamente, el sitio web de SIG mantiene una lista de implementaciones.

helm install apisix apisix/apisix \
  --namespace ingress-apisix \
  --create-namespace \
  --devel \                                                                #1
  --set gateway.type=NodePort \                                            #2
  --set gateway.http.nodePort=30800 \                                      #2
  --set ingress-controller.enabled=true \                                  #2
  --set ingress-controller.config.kubernetes.enableApiGateway=true \       #3
  --set ingressPublishService="ingress-apisix/apisix-gateway"              #4
  1. Sin la opción --devel, Helm instala la versión más reciente, que no funciona con la API Gateway
  2. El Gateway necesita ser accesible fuera del clúster de todos modos
  3. ¡Aquí es donde ocurre la magia!
  4. Volveré a esto más tarde

Verifiquemos que todo funciona:

k get all -n ingress-apisix
NAME                                             READY   STATUS    RESTARTS   AGE
pod/apisix-5fc9b45c69-cf42m                      1/1     Running   0          14m    #1
pod/apisix-etcd-0                                1/1     Running   0          14m    #2
pod/apisix-etcd-1                                1/1     Running   0          14m    #2
pod/apisix-etcd-2                                1/1     Running   0          14m    #2
pod/apisix-ingress-controller-6f8bd94d9d-wkzfn   1/1     Running   0          14m    #3

NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
service/apisix-admin                ClusterIP   10.96.69.19     <none>        9180/TCP
service/apisix-etcd                 ClusterIP   10.96.226.79    <none>        2379/TCP,2380/TCP
service/apisix-etcd-headless        ClusterIP   None            <none>        2379/TCP,2380/TCP
service/apisix-gateway              NodePort    10.96.101.224   <none>        80:30800/TCP #4
service/apisix-ingress-controller   ClusterIP   10.96.141.230   <none>        80/TCP
  1. Apache APISIX en sí
  2. Apache APISIX almacena su configuración en etcd. El chart programa tres pods por defecto, una buena práctica para manejar fallos en sistemas distribuidos
  3. Controlador de Apache APISIX: un controlador de Kubernetes es un bucle de control que mueve el estado existente hacia el estado deseado
  4. Servicio de Gateway de Apache APISIX: es el Service de tipo NodePort que instalamos a través del Helm Chart. También es el nombre que referenciamos durante la instalación del Helm Chart - ingressPublishService

En este punto, la infraestructura está lista.

Declarar la implementación del Gateway

Como mencioné anteriormente, la API hace una separación clara entre la especificación y la implementación. Sin embargo, necesitamos vincularla de alguna manera. Es responsabilidad del objeto GatewayClass:

apiVersion: gateway.networking.k8s.io/v1alpha2 #1
kind: GatewayClass #2
metadata:
  name: apisix-gateway-class #3
spec:
  controllerName: apisix.apache.org/gateway-controller #4
  1. No usamos la última versión a propósito, ya que Apache APISIX usa esta versión. Ten en cuenta que evolucionará en el (cercano) futuro
  2. Objeto GatewayClass
  3. Nómbralo como quieras; sin embargo, lo usaremos más tarde para referenciar la clase de gateway
  4. El nombre del controlador depende de la implementación. Aquí estamos usando el de Apache APISIX.

Nota que el GatewayClass tiene un alcance de todo el clúster. Este modelo nos permite declarar diferentes implementaciones de la API Gateway y usarlas en paralelo dentro del mismo clúster.

Crear el Gateway

Con Apache APISIX, es bastante sencillo:

apiVersion: gateway.networking.k8s.io/v1alpha2 #1
kind: Gateway #2
metadata:
  name: apisix-gateway
spec:
  gatewayClassName: apisix-gateway-class #3
  listeners: #4
    - name: http
      protocol: HTTP
      port: 80
  1. Mismo espacio de nombres que arriba
  2. Objeto Gateway
  3. Referencia la clase de gateway declarada anteriormente
  4. Permite algunas restricciones en este nivel para que el operador del clúster pueda evitar usos no deseados

Advertencia: La API Gateway especifica la opción de cambiar dinámicamente el puerto en el lado del operador. Al momento de escribir esto, la asignación de puertos de Apache APISIX es estática. El plan es hacerla dinámica en el futuro. Por favor, suscríbete a este issue de GitHub para seguir el progreso.

Rutas, rutas, rutas por todas partes

Hasta ahora, todo era infraestructura; finalmente podemos configurar el enrutamiento.

Quiero el mismo enrutamiento que en el post anterior; una rama /left y una right. Omitiré la última por brevedad.

apiVersion: gateway.networking.k8s.io/v1alpha2 #1
kind: HTTPRoute #2
metadata:
  name: left
spec:
  parentRefs:
    - name: apisix-gateway #3
  rules:
    - matches: #4
        - path: #4
            type: PathPrefix #4
            value: /left
      backendRefs: #5
        - name: left #5
          port: 80 #5
  1. Mismo espacio de nombres que arriba
  2. Objeto HTTPRoute
  3. Referencia el Gateway creado anteriormente
  4. Reglas de coincidencia. En nuestro caso, coincidimos con un prefijo de ruta, pero hay muchas reglas disponibles. Puedes coincidir basado en un parámetro de consulta, en un encabezado, etc.
  5. El "upstream" al que reenviar. Definimos el Service left en el post anterior del blog.

Verificar que funciona

Ahora que hemos configurado nuestras rutas, podemos verificar que funciona.

curl localhost:30800/left

Cuando instalamos el chart de Helm, le dijimos a Apache APISIX que creara un servicio NodePort en el puerto 30800. Por lo tanto, podemos usar el puerto para acceder al servicio fuera del clúster.

left

Conclusión

Hay muchas alternativas disponibles para acceder a un pod desde fuera del clúster. La CNCF agregó la mayoría de ellas para mejorar la anterior.

La API Gateway es la última propuesta en este sentido. La especificación es un trabajo en progreso y los productos están en diferentes etapas de implementación. Por esta razón, es demasiado pronto para basar tu producción en la API. Sin embargo, probablemente deberías seguir el progreso, ya que está destinada a ser una mejora considerable sobre los enfoques anteriores.

El código fuente completo para este post se puede encontrar en GitHub.

Para ir más allá:

Tags: