Implementa puertas de enlace

En esta página, se describe cómo implementar recursos de puerta de enlace de Kubernetes en Google Kubernetes Engine (GKE). Se explica cómo implementar una puerta de enlace privada y una puerta de enlace orientada a Internet para exponer aplicaciones, y se muestran algunos de los conceptos del modelo de recursos de la API de Gateway.

Si deseas ver cómo se implementan las puertas de enlace para el balanceo de cargas de varios clústeres, consulta Implementa puertas de enlace de varios clústeres. Para comprender las diferencias entre GatewayClasses, consulta Capacidades de GatewayClass.

Requisitos del controlador de la puerta de enlace de GKE

  • GKE versión 1.20 o posterior.
  • La API de la puerta de enlace solo es compatible con los clústeres nativos de VPC (aliasIP).
  • Si usas las GatewayClasses internas, se debe habilitar una subred de solo proxy.
  • Las puertas de enlace de varios clústeres y de un solo clúster se admiten en todas las regiones de Google Cloud.

Vista previa de las limitaciones y los problemas conocidos

Si bien la asistencia de GKE de la API de Gateway se encuentra en vista previa, se aplican las siguientes limitaciones:

  • Los clústeres de Autopilot no son compatibles.
  • Las GatewayClasses de GKE admiten diferentes capacidades según su balanceador de cargas subyacente. Consulta las capacidades de GatewayClass para obtener más información sobre las diferentes funciones compatibles con las GatewayClasses disponibles.
  • Los clústeres de GKE que tienen recursos Gateway de Istio o ASM generarán conflictos con los recursos de la puerta de enlace de Kubernetes cuando se usa kubectl. Es posible que kubectl get gateway no muestre tus recursos de puerta de enlace de Istio o ASM según lo previsto. Para evitar conflictos de recursos de la línea de comandos con puertas de enlace de Istio, consulta Puertas de enlace de Kubernetes y puertas de enlace de Istio.
  • Por el momento, los recursos del balanceador de cargas de Google Cloud que crean las puertas de enlace no se pueden ver en la IU de Google Cloud Console.
  • No se admite la visualización de los recursos de puerta de enlace, HTTPRoute y ServiceExport en la IU de GKE.
  • No se admite el uso del controlador de la puerta de enlace de GKE con Kubernetes en Compute Engine (Kubernetes autoadministrado).
  • No se admite la finalización del tráfico de TLS con credenciales almacenadas en secretos de Kubernetes. Sin embargo, se admite la referencia a los recursos del certificado SSL de Google Cloud para finalizar TLS.
  • No se admite la configuración de políticas de SSL o redireccionamientos HTTPS mediante el recurso FrontendConfig.
  • El recurso BackendConfig no es compatible con las GatewayClasses de varios clústeres (-mc), sin embargo, es compatible con las GatewayClasses de un solo clúster.
  • La generación automática de certificados SSL administrados por Google no es compatible. Sin embargo, se puede crear un certificado SSL administrado por Google de forma manual y hacer referencia a él mediante la opción TLS networking.gke.io/pre-shared-certs.
  • No se admiten las opciones de configuración de la capacidad de tráfico de servicio max-rate-per-endpoint, max-rate y capacity-scaler.

Instala las CRD de la API de puerta de enlace

Antes de usar recursos de puerta de enlace en GKE, debes instalar las definiciones de recursos personalizados (CRD) de la API de puertas de enlace en el clúster.

  1. Ejecuta el siguiente comando en el clúster de GKE en el que deseas implementar recursos de Gateway:

    kubectl apply -k "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.4.3"
    

    Este comando instala las CRD de v1alpha2.

    El resultado es similar a este:

    customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/referencepolicies.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/tcproutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/tlsroutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/udproutes.gateway.networking.k8s.io configured
    

GatewayClasses de GKE

Después de que un clúster de GKE detecta la existencia de CRD de la API de la puerta de enlace, el siguiente controlador de la puerta de enlace de GKE instala de forma automática las siguientes puertas de enlace de GKE. Es posible que el controlador tarde unos minutos en reconocer las CRD y en instalar GatewayClasses.

  1. Verifica las GatewayClasses disponibles con el siguiente comando:

    kubectl get gatewayclass
    

    Este resultado confirma que las GatewayClasses de GKE están listas para usarse en tu clúster:

    NAME          CONTROLLER
    gke-l7-rilb   networking.gke.io/gateway
    gke-l7-gxlb   networking.gke.io/gateway
    

    Para comprender las capacidades de cada puerta de enlace, consulta Capacidades de cada puerta de enlace.

Configura una subred de solo proxy

Si aún no lo has hecho, configura una subred de solo proxy para cada región en la que implementes puertas de enlace einternas. Esta subred se usa para proporcionar direcciones IP internas a los proxies de balanceador de cargas.

Debes crear una subred de solo proxy antes de crear Gateways que administren los balanceadores de cargas HTTP(S) internos. Cada región de una VPC en la que uses balanceadores de cargas HTTP(S) internos debe tener una subred de solo proxy.

Con el comando gcloud compute networks subnets create, se crea una subred de solo proxy.

gcloud compute networks subnets create SUBNET_NAME \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=REGION \
    --network=VPC_NETWORK_NAME \
    --range=CIDR_RANGE

Reemplaza lo siguiente:

  • SUBNET_NAME: El nombre de la subred de solo proxy
  • REGION: La región de la subred de solo proxy
  • VPC_NETWORK_NAME: El nombre de la red de VPC que contiene la subred
  • CIDR_RANGE: El rango de direcciones IP principal de la subred Debes usar una máscara de subred de un tamaño máximo de /26 a fin de que al menos 64 direcciones IP estén disponibles para los proxies de la región. La máscara de subred recomendada es /23.

Si el siguiente evento aparece en tu Gateway interna, no existe una subred de solo proxy para esa región. Para resolver este problema, implementa una subred de solo proxy.

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

Implementa una puerta de enlace interna

Un recurso de puerta de enlace representa un plano de datos que enruta el tráfico en Kubernetes. Una puerta de enlace puede representar muchos tipos diferentes de balanceo de cargas y enrutamiento según la GatewayClass de la que deriva. Para obtener más información sobre el recurso de puerta de enlace, consulta la descripción del recurso de puerta de enlace o la especificación de la API.

En este caso, el administrador del clúster de GKE quiere crear una puerta de enlace que varios equipos puedan usar para exponer sus aplicaciones de forma interna. El administrador implementa la Gateway, y los equipos de aplicaciones implementan sus rutas de forma independiente y las conectan a esta Gateway.

  1. Guarda el siguiente manifiesto de Gateway en un archivo llamado gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
    

    Explicación de los campos

    • gatewayClassName: gke-l7-rilb especifica la GatewayClass de la que deriva esta puerta de enlace. gke-l7-rilb corresponde al balanceador de cargas de HTTP(S) regional interno.
    • port: 80 especifica que la puerta de enlace expone solo el puerto 80 para escuchar el tráfico HTTP.
  2. Implementa la puerta de enlace en tu clúster:

    kubectl apply -f gateway.yaml
    
  3. Verifica que la puerta de enlace se haya implementado de forma correcta. La implementación de todos sus recursos puede llevar unos minutos.

    kubectl describe gateways.gateway.networking.k8s.io internal-http
    

    El resultado se parece al siguiente:

    Name:         internal-http
    Namespace:    default
    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  192.168.1.14
      Conditions:
        Last Transition Time:  1970-01-01T00:00:00Z
        Message:               Waiting for controller
        Reason:                NotReconciled
        Status:                False
        Type:                  Scheduled
    Events:
      Type    Reason  Age                From                       Message
      ----    ------  ----               ----                       -------
      Normal  ADD     92s                networking.gke.io/gateway  test/internal-http
      Normal  UPDATE  45s (x3 over 91s)  networking.gke.io/gateway  test/internal-http
      Normal  SYNC    45s                networking.gke.io/gateway  SYNC on test/internal-http was a success
    

    En este punto, hay una puerta de enlace implementada en tu clúster que aprovisionó un balanceador de cargas y una dirección IP. Sin embargo, la puerta de enlace no tiene rutas y, por lo tanto, aún no sabe cómo debe enviar tráfico a los backends. Sin rutas, todo el tráfico se dirige a un backend predeterminado, que muestra un HTTP 404. A continuación, implementarás una aplicación y rutas, que le indican a la puerta de enlace cómo llegar a los backends de aplicaciones.

Implementa las aplicaciones de demostración

Los equipos de aplicaciones pueden implementar sus aplicaciones y rutas independientemente de la implementación de puertas de enlace. En algunos casos, es posible que el equipo de aplicaciones también desee poseer la puerta de enlace y, luego, implementarla como un recurso dedicado a sus aplicaciones. Consulta Vinculación de rutas para ver diferentes modelos de propiedad de puertas de enlace y rutas. En este ejemplo, el equipo de la tienda implementa su aplicación y una HTTPRouter adjunta para exponer su app a través de la puerta de enlace internal-http creada en la sección anterior.

El recurso HTTPRoute tiene muchos campos configurables para la coincidencia de tráfico. Para ver una explicación de los campos de HTTPRoute, consulta la especificación de API.

  1. Implementa la aplicación de almacenamiento (implementaciones store-v1, store-v2 y store-german) en su clúster:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
    

    Esto crea tres implementaciones y tres servicios, llamados store-v1, store-v2 y store-german

  2. Confirma que la aplicación se haya implementado correctamente:

    kubectl get pod
    

    El resultado se parece al siguiente después de que se ejecuta la aplicación:

    NAME                        READY   STATUS    RESTARTS   AGE
    store-german-66dcb75977-5gr2n   1/1     Running   0          38s
    store-v1-65b47557df-jkjbm       1/1     Running   0          14m
    store-v2-6856f59f7f-sq889       1/1     Running   0          14m
    
  3. Valida que también se hayan implementado los servicios:

    kubectl get service
    

    El resultado se parece al siguiente y muestra un servicio para cada implementación de almacenamiento:

    NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    store-german   ClusterIP   10.48.3.183   <none>        8080/TCP   4s
    store-v1       ClusterIP   10.48.2.224   <none>        8080/TCP   5s
    store-v2       ClusterIP   10.48.4.48    <none>        8080/TCP   5s
    

Balanceo de cargas nativo del contenedor

El controlador de la puerta de enlace de GKE usa el balanceo de cargas nativo del contenedor de forma predeterminada. Esto significa que el tráfico con balanceo de cargas se envía directamente a las direcciones IP del Pod. El balanceador de cargas tiene visibilidad directa de las direcciones IP del Pod para que el tráfico no desvíe el balanceo de cargas del Servicio de Kubernetes. Esto conduce a un tráfico más eficiente, estable y comprensible. Las GatewayClasses gke-l7-* no admiten el balanceo de cargas basado en grupos de instancias.

Las puertas de enlace de GKE no requieren ninguna anotación especial especificada por el usuario en los servicios. El controlador de puerta de enlace de GKE anota de forma automática cualquier servicio al que se hace referencia mediante un HTTPRoute con referencias a los NEG del servicio, como en el siguiente ejemplo:

Name:              store-v1
Namespace:         default
Annotations:       cloud.google.com/neg: {"exposed_ports":{"8080":{}}}
                   cloud.google.com/neg-status: {"network_endpoint_groups":{"8080":"k8s1-cb368ccb-default-foo-v1-8080-f376ae25"},"zones":["us-central1-a"]}
...

Implementa la HTTPRoute

Los recursos de ruta definen reglas específicas del protocolo para asignar tráfico de una puerta de enlace a backends de Kubernetes. El recurso HTTPRoute realiza coincidencias y filtros de tráfico HTTP y HTTPS, y es compatible con todas las GatewayClasses gke-l7.

En esta sección, implementarás un HTTPRoute, que programa el Gateway con las reglas de enrutamiento necesarias para llegar a la aplicación de almacenamiento.

  1. Guarda el siguiente manifiesto de HTTPRoute en un archivo llamado store-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: store
    spec:
     parentRefs:
     - kind: Gateway
       name: internal-http
     hostnames:
     - "store.example.com"
     rules:
     - backendRefs:
       - name: store-v1
         port: 8080
     - matches:
       - headers:
         - name: env
           value: canary
       backendRefs:
       - name: store-v2
         port: 8080
     - matches:
       - path:
           value: /de
       backendRefs:
       - name: store-german
         port: 8080
    
  2. Implementa la HTTProute en tu clúster:

    kubectl apply -f store-route.yaml
    

La HTTPRoute store está vinculada a la puerta de enlace internal-http, por lo que estas reglas de enrutamiento se configuran en el balanceador de cargas subyacente como se muestra en este diagrama:

Las reglas de enrutamiento configuradas por la tienda de HTTPRoute

Estas reglas de enrutamiento procesarán el tráfico HTTP de la siguiente manera:

  • El tráfico a store.example.com/de se dirige al servicio store-german.
  • El tráfico a store.example.com con el encabezado HTTP "env: canary" se dirige al servicio store-v2.
  • El tráfico restante para store.example.com se dirige al servicio store-v1.

Vinculación de ruta

Las puertas de enlace usan vinculaciones de rutas para hacer coincidir rutas con puertas de enlace. Cuando una ruta se vincula a una puerta de enlace, el proxy o el balanceador de cargas subyacente se programan con las reglas de enrutamiento especificadas en la ruta. Los recursos de ruta y puerta de enlace tienen controles integrados para permitir o limitar la forma en que se seleccionan, lo que determina la vinculación.

La HTTPRoute store está vinculada a la Gateway internal-http mediante la propiedad parentsRefs:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: internal-http
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      kinds:
      - kind: HTTPRoute
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store
  spec:
    parentRefs:
    - name: internal-http

Una HTTPRouter se conecta a una Gateway particular a través de la propiedad parentsRef. Si la Gateway está configurada para permitir la conexión de ese espacio de nombres y tipo de ruta específicos, la conexión se realiza de forma correcta. De forma predeterminada, la Gateway confía en todas las rutas del mismo espacio de nombres. Las rutas conectadas a Gateways configuran las reglas de enrutamiento del balanceador de cargas subyacente. Una ruta se puede conectar a varias Gateways, y las Gateways también pueden tener varias rutas conectadas.

Cuando muchas rutas se conectan a la misma Gateway, el controlador de Gateway de GKE combina estas rutas en una sola configuración de enrutamiento para el balanceador de cargas subyacente. Esto es lo que permite que diferentes equipos compartan la misma infraestructura subyacente, mientras controlan su parte de la configuración de enrutamiento de forma independiente.

El controlador de puerta de enlace de GKE implementa una lógica de combinación, prioridad y validación estricta de la ruta, que proporciona una combinación predecible entre rutas y evita que las rutas no válidas interrumpan la configuración del balanceador de cargas subyacente. Para obtener más detalles, consulta Combinación, prioridad y validación de rutas.

Para obtener instrucciones sobre cómo implementar una segunda HTTPRoute que también use la puerta de enlace HTTP interna, consulta la sección Puertas de enlace compartidas.

Envía tráfico a tu aplicación

Ahora que la puerta de enlace, la ruta y la aplicación están implementadas en el clúster, puedes pasar el tráfico a la aplicación.

  1. Valida que la HTTPRoute de almacenamiento se haya aplicado correctamente. Los eventos se emiten en la ruta cuando se vincula a una puerta de enlace de forma correcta.

    kubectl describe httproute.gateway.networking.k8s.io store
    

    La sección de eventos del resultado incluye eventos como los siguientes, si HTTPRoute vinculado a la puerta de enlace:

    Events:
    Type    Reason  Age   From                              Message
    ----    ------  ----  ----                              -------
    Normal  ADD     11m   networking.gke.io/gateway         default/store
    Normal  ADD     11m   multi-cluster-ingress-controller  default/store
    
  2. Recupera la dirección IP de la puerta de enlace para que puedas enviar tráfico a tu aplicación:

    kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}"
    

    El resultado es una dirección IP.

  3. Envía tráfico a esta dirección IP desde la shell en una instancia de máquina virtual (VM) con conectividad al clúster. Puedes crear una VM para este fin. Esto es necesario porque la puerta de enlace tiene una dirección IP interna y solo se puede acceder desde tu red de VPC. Debido a que internal-http es un balanceador de cargas regional, la shell del cliente debe estar dentro de la misma región que el clúster de GKE.

    Debido a que no eres propietario del nombre de host example.com, configura el encabezado del host de forma manual para que se pueda observar el enrutamiento de tráfico. Primero, intenta solicitar store.example.com:

    curl -H "host: store.example.com" VIP
    

    Reemplaza VIP por la dirección IP del paso anterior.

    El resultado de la app de demostración muestra información sobre la ubicación en la que se ejecuta la app:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.church-243723.internal",
      "pod_name": "store-v1-84b47c7f58-pmgmk",
      "pod_name_emoji": "💇🏼‍♀️",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:31:17",
      "zone": "us-central1-a"
    }
    
  4. Para probar la coincidencia de ruta de acceso, ve a la versión en alemán del servicio de almacenamiento en store.example.com/de:

    curl -H "host: store.example.com" VIP/de
    

    El resultado confirma que un pod store-german entregó la solicitud:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "Gutentag!", 
      "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.church-243723.internal",
      "pod_name": "store-german-5cb6474c55-lq5pl", 
      "pod_name_emoji": "🧞‍♀",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:35:37",
      "zone": "us-central1-a"
    }
    
  5. Por último, usa el encabezado HTTP env: canary para enviar tráfico a la versión canary del servicio de almacenamiento:

    curl -H "host: store.example.com" -H "env: canary " VIP
    

    El resultado confirma que un pod store-v2 entregó la solicitud:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v2", 
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.church-243723.internal",
      "pod_name": "store-v2-5788476cbd-s9thb", 
      "pod_name_emoji": "👩🏿🦰",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:38:26",
      "zone": "us-central1-a"
    }
    

Puertas de enlace compartidas

Las API de Gateway usan recursos separados, de puerta de enlace y de ruta, para implementar balanceadores de cargas y reglas de enrutamiento. Esto difiere de Ingress, que combina todo en un recurso. Cuando se divide la responsabilidad entre los recursos, la puerta de enlace permite que el balanceador de cargas y sus reglas de enrutamiento se implementen por separado y que diferentes usuarios o equipos lo implementen. Esto permite que las Gateways se conviertan en Gateways compartidas que se conectan a muchas rutas diferentes que pueden ser de total propiedad y administración de equipos independientes, incluso en diferentes espacios de nombres.

En los pasos anteriores, el equipo de “tienda” implementó su aplicación, store.example.com. Luego, el equipo independiente del “sitio” implementa su aplicación, site.example.com, detrás de la misma Puerta de enlace internal-http que usa la misma dirección IP.

Implementa rutas en una Puerta de enlace compartida

En este ejemplo, el equipo del sitio implementa su aplicación, servicios y una HTTPRoute correspondiente para hacer coincidir el tráfico de Puerta de enlace con esos servicios.

  1. Implementa la aplicación de ejemplo

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/site.yaml
    
  2. Guarda el siguiente manifiesto de HTTPRoute en un archivo llamado site-route.yaml:

    Esta HTTPRouter site coincide con todo el tráfico de site.example.com y lo enruta al servicio site-v1. Al igual que la HTTPRoute de almacenamiento, la HTTPRoute del sitio especifica la Gateway internal-http. El controlador de Gateway de GKE combina estas HTTPRoutes en un solo URLmap subyacente con rutas para site.example.com y store.example.com.

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
     name: site
    spec:
     hostnames:
     - "site.example.com"
     rules:
     - backendRefs:
       - name: site-v1
         port: 8080
    
  3. Implementa la HTTPRoute en tu clúster:

    kubectl apply -f site-route.yaml
    
  4. Con ambas HTTPRoutes implementadas, la lógica de enrutamiento debe parecerse al siguiente diagrama. El tráfico de site.example.com debe ir a los Pods de site-v1, store.example.com debe ir a los Pods de store-v1, store-v2 o store-german.

    Una imagen de las HTTPRoutes de almacenamiento y sitio vinculadas a la misma puerta de enlace

  5. Verifica que la HTTPRoute se haya vinculado correctamente a la puerta de enlace internal-http:

    kubectl describe httproute.gateway.networking.k8s.io site
    

    El resultado se parece al siguiente si la HTTPRoute se vinculó correctamente a la puerta de enlace.

    Status:
      Gateways:
        Conditions:
          Last Transition Time:  2021-04-19T16:13:46Z
          Message:               Route admitted
          Observed Generation:   1
          Reason:                RouteAdmitted
          Status:                True
          Type:                  Admitted
        Gateway Ref:
          Name:       internal-http
          Namespace:  default
    Events:
      Type    Reason  Age                 From                              Message
      ----    ------  ----                ----                              -------
      Normal  ADD     60m                 networking.gke.io/gateway         foo/foo-route
    

    Si la condición admitida para la puerta de enlace http interna es True, esto indica que HTTPRoute/site se vinculó correctamente al http interno.

    Una configuración no válida, las referencias a los servicios de Kubernetes inexistentes, el etiquetado incorrecto de la puerta de enlace o el conflicto con otras rutas pueden provocar que se rechace la HTTPRoute con una puerta de enlace.

    Para obtener más detalles sobre cómo interpretar el estado de las rutas, consulta la sección estado de la ruta.

  6. Después de verificar que la ruta site se vinculó correctamente, envía tráfico a la puerta de enlace para confirmar que se está enrutando de forma correcta. Envía tráfico desde una VM en la misma red de VPC que la puerta de enlace. Envía una solicitud HTTP a site.example.com y store.example.com para validar las respuestas:

    curl -H "host: site.example.com" VIP
    curl -H "host: store.example.com" VIP
    

Estado de la ruta

Los recursos HTTPRoute emiten condiciones y eventos para ayudar a los usuarios a comprender el estado de la configuración aplicada. Juntos indican si una ruta se vinculó correctamente a una o más puertas de enlace, o si se rechazó.

Condiciones de HTTPRoute

Las condiciones de HTTPRoute indican el estado de la vinculación de ruta entre cualquier puerta de enlace a la que está vinculada una ruta. Debido a que una ruta se puede vincular a varias puertas de enlace, esta es una lista de puertas de enlace y las condiciones individuales entre la ruta y cada puerta de enlace.

  • Admitted=True indica que el HTTPRoute se vinculó correctamente a una puerta de enlace.
  • Admitted=False indica que se rechazó la HTTPRoute de esta vinculación con esta puerta de enlace.

Si no hay puertas de enlace enumeradas en el encabezado Gateway bindings, es probable que tus etiquetas de ruta y selectores de etiqueta de puerta de enlace no coincidan. Esto significa que ninguna puerta de enlace está seleccionando tu ruta y, por lo tanto, su configuración no se aplica en ningún lugar.

Eventos de HTTPRouter

Los eventos de HTTPRoute proporcionan más detalles sobre el estado de la ruta. Existen algunas clases o razones bajo las cuales se agrupan los eventos:

  • Los eventos ADD se activan mediante un recurso que se agrega.
  • Los eventos UPDATE se activan mediante un recurso que se actualiza.
  • Los eventos SYNC se activan mediante una conciliación periódica.

Implementa una puerta de enlace externa

En el siguiente ejemplo, se muestra cómo implementar una puerta de enlace que se usará para el balanceo de cargas de Internet externo. Se muestra cómo configurar la TLS para que la conexión del cliente proteja la puerta de enlace. En este ejemplo, se usa la GatewayClass gke-l7-gxlb, pero estos conceptos de TLS se aplican de la misma manera para todas las GatewayClasses de gke-l7-*.

La aplicación implementada anteriormente es un requisito para este ejemplo. Si aún no lo has hecho, regresa e implementa esta aplicación en tu clúster antes de continuar.

Las GatewayClasses gke-l7-gxlb y gke-l7-gxlb-mc implementan un balanceador de cargas HTTP(S) externo global (clásico) para el tráfico orientado a Internet. Tienen una funcionalidad equivalente, excepto que gke-l7-gxlb-mc también admite casos de uso de varios clústeres porque puede balancear las cargas de las aplicaciones en varios clústeres de GKE. Para obtener una comparación con otras GatewayClasses, consulta Capacidades de GatewayClass.

TLS entre el cliente y la puerta de enlace

Un balanceador de cargas de HTTP(S) externo global (clásico) actúa como un proxy entre tus clientes y tu aplicación. Si deseas aceptar solicitudes HTTPS de los clientes, el balanceador de cargas debe contar con un certificado para que pueda demostrar su identidad a los clientes. El balanceador de cargas también debe tener una clave privada para completar el protocolo de enlace HTTPS. El certificado y la clave privada se denominan credenciales de TLS.

El certificado y la clave TLS se almacenan como recursos de certificado SSL de Google Cloud.

En el siguiente manifiesto de Gateway, se muestra cómo se configuró TLS:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: external-http
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      kinds:
      - kind: HTTPRoute
    tls:
      mode: Terminate
      options:
        networking.gke.io/pre-shared-certs: store-example-com

Estos elementos son necesarios en una puerta de enlace que usa TLS:

  • El puerto y el protocolo del objeto de escucha de la puerta de enlace deben configurarse en 443 y HTTPS.
  • El campo listener.tls.mode debe configurarse como Terminate.
  • Se debe hacer referencia a las credenciales de TLS en el bloque listeners.tls.

En el manifiesto de ejemplo, se hace referencia a un recurso de certificado SSL llamado store-example-com. Este certificado finaliza todo el tráfico al puerto 443 de esta puerta de enlace.

Crea y almacena un certificado TLS

Existen muchas formas de generar certificados TLS. Se pueden generar de forma manual en la línea de comandos, mediante certificados administrados por Google o de forma interna en el sistema de infraestructura de clave pública (PKI) de tu empresa. En este ejemplo, generamos manualmente un certificado autofirmado. Los certificados autofirmados no se suelen usar para servicios públicos, pero demuestran estos conceptos con mayor facilidad.

  1. Sigue el Paso 1: Crea una clave privada y un certificado de la guía de certificados SSL autoadministrados. Esto genera un certificado autofirmado y un par de claves mediante la línea de comandos. Usa la siguiente configuración de OpenSSL a fin de crear un certificado autofirmado para store.example.com.

    [req]
    default_bits              = 2048
    req_extensions            = extension_requirements
    distinguished_name        = dn_requirements
    prompt                    = no
    
    [extension_requirements]
    basicConstraints          = CA:FALSE
    keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName            = @sans_list
    
    [dn_requirements]
    0.organizationName        = example
    commonName                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    

    Guarda el certificado y los archivos de claves como cert.pem y key.pem, respectivamente. No avances al paso 2 de las instrucciones para usar certificados SSL autoadministrados.

  2. Guarda tus credenciales de certificado como un recurso de certificado SSL global:

    gcloud compute ssl-certificates create store-example-com \
        --certificate=cert.pem \
        --private-key=key.pem \
        --global
    

    El nombre de GatewayClass indica el tipo de recurso de certificado SSL que se puede usar con puertas de enlace de esa clase. El permiso y la ubicación del certificado SSL deben coincidir con el permiso y la ubicación de la puerta de enlace que lo usa. Por ejemplo, una puerta de enlace regional no puede usar un certificado SSL global.

    En la siguiente tabla, se muestran los requisitos de ubicación y alcance para los recursos de certificado SSL que usa Puertas de enlace:

    GatewayClasses Alcance de los certificados SSL Ubicación del certificado SSL
    • gke-l7-rilb
    • gke-l7-rilb-mc
    Certificado SSL regional Debe ser la misma región que la puerta de enlace
    • gke-l7-gxlb
    • gke-l7-gxlb-mc
    Certificado SSL global Global

Implementa la Gateway

  1. Guarda el siguiente manifiesto de Gateway, que usa la GatewayClass gke-l7-gxlb, como external-gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-gxlb
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    Este manifiesto de las puerta de enlace externo difiere del ejemplo de puertas de enlace interno anterior de varias maneras:

    • Usa la GatewayClass gke-l7-gxlb, que implementa un balanceador de cargas de HTTP(S) externo global (clásico).
    • Su puerto y protocolo están configurados en 443 y HTTPS.
    • La sección tls del manifiesto está configurada para finalizar TLS con un recurso de certificado SSL.
  2. Implementa esta puerta de enlace en tu clúster de GKE:

    kubectl apply -f external-gateway.yaml
    
  3. Guarda el siguiente manifiesto de HTTPRoute como store-external-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. Implementa la HTTPRoute en tu clúster:

    kubectl apply -f store-external-route.yaml
    

    La puerta de enlace gke-l7-gxlb puede tardar varios minutos en implementarse completamente.

  5. Envía una solicitud a través de Internet para verificar que la puerta de enlace funcione.

    1. Guarda el archivo cert.pem que generaste antes en la máquina que usas para conectarte a la puerta de enlace. Debido a que la puerta de enlace usa un certificado autofirmado, este es necesario para autenticar la puerta de enlace.

    2. Obtén la dirección IP del balanceador de cargas.

      kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"
      

      El comando genera la dirección IP del balanceador de cargas. Esta es una dirección IP pública, por lo que cualquier cliente con acceso a Internet puede conectarse a ella.

    3. Usa curl para acceder al dominio de la puerta de enlace. Debido a que el DNS no está configurado para este dominio, usa la opción --resolve para indicarle a curl que resuelva el nombre de dominio a la dirección IP de la puerta de enlace:

      curl https://store.example.com --resolve store.example.com:443:VIP --cacert cert.pem -v
      

      Reemplaza VIP por la dirección IP del balanceador de cargas.

    4. El resultado detallado de curl incluye un protocolo de enlace TLS exitoso seguido de una respuesta de la aplicación, como el siguiente resultado. Esto demuestra que TLS se cierra en la puerta de enlace correctamente y que la aplicación responde al cliente de forma segura.

      ...
      * TLSv1.2 (OUT), TLS handshake, Client hello (1):
      * TLSv1.2 (IN), TLS handshake, Server hello (2):
      * TLSv1.2 (IN), TLS handshake, Certificate (11):
      * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
      * TLSv1.2 (IN), TLS handshake, Server finished (14):
      * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
      * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
      * TLSv1.2 (OUT), TLS handshake, Finished (20):
      * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
      * TLSv1.2 (IN), TLS handshake, Finished (20):
      * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
      * ALPN, server accepted to use h2
      * Server certificate:
      *  subject: O=example; CN=store.example.com
      *  start date: Apr 19 15:54:50 2021 GMT
      *  expire date: Apr 19 15:54:50 2022 GMT
      *  common name: store.example.com (matched)
      *  issuer: O=example; CN=store.example.com
      *  SSL certificate verify ok.
      ...
      {
        "cluster_name": "gw",
        "host_header": "store.example.com",
        "metadata": "store-v1",
        "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
        "pod_name": "store-v1-84b47c7f58-tj5mn",
        "pod_name_emoji": "😍",
        "project_id": "agmsb-k8s",
        "timestamp": "2021-04-19T16:30:08",
        "zone": "us-west1-a"
      }
      

BackendConfig con la puerta de enlace

GatewayClasses gke-l7 permiten admitir el recurso BackendConfig para personalizar la configuración del backend a nivel de servicio. Esto requiere la anotación del servicio cloud.google.com/backend-config para hacer referencia al recurso BackendConfig. En el siguiente ejemplo, la verificación de estado del balanceador de cargas y la configuración de vaciado de conexiones se personalizan para el servicio de store-v1.

apiVersion: v1
kind: Service
metadata:
  name: store-v1
  annotations:
    cloud.google.com/backend-config: '{"default": "store-backendconfig"}'
spec:
  selector:
    app: store
    version: v1
  ports:
  - port: 8080
    targetPort: 8080
---
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: store-backendconfig
spec:
  healthCheck:
    checkIntervalSec: 15
    port: 15020
    type: HTTPS
    requestPath: /healthz
  connectionDraining:
    drainingTimeoutSec: 60

Consulta Configura las funciones de Ingress a través de parámetros de BackendConfig para obtener más información sobre cómo usar el recurso BackendConfig.

Direccionamiento IP de puerta de enlace

Cada puerta de enlace tiene una dirección IP en la que escucha el tráfico. Si no se especifica ninguna dirección en la puerta de enlace, la puerta de enlace aprovisiona una dirección IP de forma automática. Las direcciones estáticas también se pueden aprovisionar de forma previa para que el ciclo de vida de la dirección IP sea independiente de la puerta de enlace.

Después de implementar una puerta de enlace, su dirección IP se muestra en el campo de estado:

kind: Gateway
...
status:
  addresses:
    - value: 10.15.32.3

Según la GatewayClass, la dirección IP se asigna desde las siguientes subredes:

GatewayClasses Grupo de direcciones IP predeterminado
  • gke-l7-rilb
  • gke-l7-rilb-mc
Direcciones IP privadas regionales del rango de subredes del nodo del clúster de GKE
  • gke-l7-gxlb
  • gke-l7-gxlb-mc
Direcciones IP públicas globales de los rangos de IP públicas de Google

Puedes especificar una dirección IP de dos maneras:

  • addresses.IPAddress: te permite especificar una dirección IP en el momento de la implementación de la puerta de enlace. La dirección IP se puede configurar en lugar de aprovisionarse de forma automática, pero la dirección IP tiene el mismo ciclo de vida que la puerta de enlace y se libera si se borra la puerta de enlace.

  • addresses.NamedAddress: te permite especificar una dirección IP sin importar la puerta de enlace. Puedes crear un recurso de dirección IP estática antes de la implementación de la puerta de enlace y de que la NamedAddress haga referencia al recurso. Puedes volver a usar la dirección IP estática incluso si se borra la puerta de enlace.

Para configurar una IPAddress, especifica la dirección IP en el campo addresses de la puerta de enlace que implementas.

  1. Implementa la siguiente puerta de enlace interna y especifica 10.0.0.3 como la dirección IP estática:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
      addresses:
      - type: IPAddress
        value: 10.0.0.3
    

    Una NamedAddress requiere que aprovisiones una IP estática fuera de la implementación de la puerta de enlace. Esto requiere dos pasos separados:

  2. Crea un recurso de dirección IP estática. En este caso, se implementa una puerta de enlace interna y regional, por lo que se necesita una dirección IP regional interna correspondiente.

    gcloud compute addresses create ADDRESS_NAME \
        --region REGION \
        --subnet SUBNET \
        --project PROJECT_ID
    

    Cuando uses puertas de enlace regionales, reemplaza PROJECT_ID y REGION por el proyecto y la región en los que se ejecuta el clúster de GKE. Las puertas de enlace globales y externas no requieren una especificación de región o subred.

  3. Para implementar la puerta de enlace, haz referencia al mismo nombre de recurso de dirección que NamedAddress.

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
      addresses:
      - type: NamedAddress
        value: ADDRESS_NAME
    

Combinación, prioridad y validación de rutas

Prioridad de ruta

La API de Gateway define reglas de prioridad estrictas que indican cómo el tráfico coincide con las rutas que tienen reglas de enrutamiento superpuestas. La prioridad entre dos HTTPRoutes superpuestas es la siguiente:

  1. Combinación de nombres de host: La coincidencia de nombres de host más larga o más específica.
  2. Combinación de rutas de acceso: La coincidencia de rutas de acceso más larga o más específica.
  3. Combinación de encabezados: La mayor cantidad de encabezados HTTP que coinciden.
  4. Conflicto: Si las tres reglas anteriores no establecen prioridad, la prioridad va al recurso HTTPRouter con la marca de tiempo más antigua.

Combinación de rutas

Para las GatewayClasses gke-l7, todas las HTTPRouters de una puerta de enlace determinada se combinan en el mismo recurso de mapa de URL. La manera en que las HTTPRoutes se combinan depende del tipo de superposición entre las HTTPRoutes. La HTTPRoute del ejemplo anterior se puede dividir en tres HTTPRoutes diferentes para ilustrar la combinación y la prioridad de rutas:

  1. Combinación de rutas: Las tres HTTPRoutes se conectan con la misma Gateway internal-http, por lo que se combinarán.
  2. Combinación de nombres de host: Las tres rutas coinciden para store.example.com, por lo que se combinan sus reglas de nombre de host.
  3. Combinación de rutas: tore-german-route tiene una ruta de acceso /de más específica, por lo que no se combina más. store-v1-route y store-v2-route también coinciden en la misma ruta /*, por lo que se combinan en la ruta.
  4. Combinación de encabezados: store-v2-route tiene un conjunto más específico de coincidencias de encabezados HTTP que store-v1-route, por lo que no se combinan más.
  5. Conflicto: Debido a que las Routes se pueden combinar en el nombre de host, la ruta de acceso y los encabezados, no hay conflictos, y todas las reglas de enrutamiento se aplicarán al tráfico.

La única HTTPRoute que se usa en el ejemplo anterior es equivalente a estas tres rutas separadas:

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-v1-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - backendRefs:
    - kind: Service
      name: store-v1
      port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-v2-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - matches:
    - headers:
      - type: Exact
        name: env
        value: canary
    backendRefs:
    - kind: Service
      name: store-v2
      port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-german-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /de
    backendRefs:
    - kind: Service
      name: store-german
      port: 8080

Backend predeterminado de la puerta de enlace

Todas las GatewayClasses gke-l7 tienen un backend predeterminado implícito que muestra un HTTP 404 al tráfico no coincidente. Es posible personalizar el backend predeterminado con una ruta predeterminada explícita que envíe tráfico no coincidente a un servicio proporcionado por el usuario. La siguiente HTTPRoute es un ejemplo de cómo personalizar el backend predeterminado. Si se aplica, tendrá prioridad sobre el backend predeterminado implícito:

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: custom-default-backend
  labels:
    gateway: my-gateway
spec:
  rules:
  - backendRefs:
    - name: my-custom-default-backend-service
      port: 8080

Esta HTTPRoute coincide con todo el tráfico de una puerta de enlace en particular. Solo puede haber una HTTPRoute por puerta de enlace o, de lo contrario, entrarán en conflicto y se aplicará el orden de prioridad.

Un backend predeterminado explícito también es una estrategia efectiva para evitar que alguien cree de forma accidental una ruta predeterminada que recibe tráfico de agujeros negros en una puerta de enlace. Debido a que una HTTPRoute explícita predeterminada es el recurso más antiguo, siempre tendrá prioridad sobre cualquier HTTPRoute nuevo que tenga reglas de enrutamiento en conflicto.

Puertas de enlace de Kubernetes y puertas de enlace de Istio

Ten en cuenta que la API de Kubernetes Gateway y la API de Istio tienen un recurso llamado Gateway. Si bien realizan funciones similares, no son el mismo recurso. Si usas Istio y la API de Gateway en el mismo clúster de Kubernetes, estos nombres se superpondrán cuando uses kubectl en la línea de comandos. kubectl get gateway puede mostrar los recursos de la puerta de enlace de Kubernetes y no los de la puerta de enlace de Istio, o viceversa.

$ kubectl api-resources
NAME       SHORTNAMES   APIGROUP                       NAMESPACED   KIND
gateways   gw           networking.istio.io/v1beta1            true         Gateway
gateways   gtw          networking.k8s.io/v1alpha2           true         Gateway

Para los clústeres de GKE 1.20 y versiones posteriores, el controlador de puerta de enlace de GKE instala de forma automática el recurso gateway.networking.k8s.io/v1alpha2 en los clústeres. Si usas Istio y actualizas a GKE 1.20 y versiones posteriores, se recomienda comenzar a usar el nombre corto del recurso de Gateway o especificar el grupo de API. El nombre corto de una puerta de enlace de Kubernetes es gtw, y el nombre corto de una puerta de enlace de Istio es gw. Los siguientes comandos muestran los recursos de puerta de enlace de Kubernetes y de puerta de enlace de Istio, respectivamente.

# Kubernetes Gateway
$ kubectl get gtw
NAME                        CLASS
multi-cluster-gateway       gke-l7-gxlb-mc

$ kubectl get gateway.networking.x-k8s.io
NAME                        CLASS
multi-cluster-gateway       gke-l7-gxlb-mc

# Istio Gateway
$ kubectl get gw
NAME               AGE
bookinfo-gateway   64m

$ kubectl get gateway.networking.istio.io
NAME               AGE
bookinfo-gateway   64m

¿Qué sigue?