Desplegar una pasarela de varios clústeres para el balanceo de carga basado en la capacidad

En este documento se explica cómo desplegar una aplicación de muestra en dos clústeres de GKE de diferentes regiones y se muestra cómo Multi-cluster Gateway enruta el tráfico de forma inteligente cuando supera los límites de capacidad del servicio.

El balanceo de carga basado en la capacidad es una función de las pasarelas de varios clústeres que te ayuda a crear aplicaciones fiables y resistentes. Si defines la capacidad de tus servicios, puedes protegerlos de la sobrecarga y ofrecer una experiencia coherente a tus usuarios. Cuando un servicio de un clúster alcanza su capacidad, el balanceador de carga redirige automáticamente el tráfico a otro clúster con capacidad disponible. Para obtener más información sobre la gestión del tráfico, consulta Gestión del tráfico de GKE.

En este tutorial, usarás una aplicación store de ejemplo para simular una situación real en la que un servicio de compras online es propiedad de equipos independientes y está gestionado por ellos, y se despliega en una flota de clústeres de GKE compartidos.

Antes de empezar

Las pasarelas multiclúster requieren cierta preparación del entorno antes de poder implementarse. Antes de continuar, sigue los pasos que se indican en el artículo Preparar el entorno para usar Gateways multiclúster:

  1. Despliega clústeres de GKE.

  2. Registra tus clústeres en una flota (si aún no lo has hecho).

  3. Habilita los controladores de servicio y de pasarela de varios clústeres.

Por último, consulta las limitaciones y los problemas conocidos del controlador de Gateway de GKE antes de usarlo en tu entorno.

Desplegar el balanceo de carga basado en la capacidad

En el ejercicio de esta sección se muestran los conceptos de balanceo de carga global y capacidad de servicio desplegando una aplicación en dos clústeres de GKE de diferentes regiones. El tráfico generado se envía a varios niveles de solicitudes por segundo (RPS) para mostrar cómo se equilibra la carga del tráfico en los clústeres y las regiones.

En el siguiente diagrama se muestra la topología que vas a implementar y cómo se desborda el tráfico entre clústeres y regiones cuando el tráfico ha superado la capacidad del servicio:

Tráfico que se desborda de un clúster a otro

Prepara tu entorno

  1. Sigue los pasos que se indican en el artículo Preparar el entorno para usar Gateways multiclúster.

  2. Confirma que los recursos de GatewayClass están instalados en el clúster de configuración:

    kubectl get gatewayclasses --context=gke-west-1
    

    El resultado debería ser similar al siguiente:

    NAME                                  CONTROLLER                  ACCEPTED   AGE
    gke-l7-global-external-managed        networking.gke.io/gateway   True       16h
    gke-l7-global-external-managed-mc     networking.gke.io/gateway   True       14h
    gke-l7-gxlb                           networking.gke.io/gateway   True       16h
    gke-l7-gxlb-mc                        networking.gke.io/gateway   True       14h
    gke-l7-regional-external-managed      networking.gke.io/gateway   True       16h
    gke-l7-regional-external-managed-mc   networking.gke.io/gateway   True       14h
    gke-l7-rilb                           networking.gke.io/gateway   True       16h
    gke-l7-rilb-mc                        networking.gke.io/gateway   True       14h
    

Desplegar una aplicación

Despliega el servidor de la aplicación web de ejemplo en ambos clústeres:

kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml

El resultado debería ser similar al siguiente:

namespace/store created
deployment.apps/store created

Desplegar un servicio, una pasarela y una ruta HTTP

  1. Aplica el siguiente manifiesto Service a los clústeres gke-west-1 y gke-east-1:

    cat << EOF | kubectl apply --context gke-west-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    
    cat << EOF | kubectl apply --context gke-east-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    

    El servicio se anota con max-rate-per-endpoint definido en 10 solicitudes por segundo. Con 2 réplicas por clúster, cada servicio tiene una capacidad de 20 RPS por clúster.

    Para obtener más información sobre cómo elegir un nivel de capacidad de servicio, consulta Determinar la capacidad de un servicio.

  2. Aplica el siguiente manifiesto Gateway al clúster de configuración, gke-west-1 en este ejemplo:

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    

    El manifiesto describe una Gateway externa, global y multiclúster que implementa un balanceador de carga de aplicación externo con una dirección IP accesible públicamente.

  3. Aplica el siguiente manifiesto HTTPRoute al clúster de configuración, gke-west-1 en este ejemplo:

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
      labels:
        gateway: store
    spec:
      parentRefs:
      - kind: Gateway
        namespace: traffic-test
        name: store
      rules:
      - backendRefs:
        - name: store
          group: net.gke.io
          kind: ServiceImport
          port: 8080
    EOF
    

    El manifiesto describe un HTTPRoute que configura la Gateway con una regla de enrutamiento que dirige todo el tráfico al ServiceImport de la tienda. El store ServiceImport agrupa los store pods de servicio de ambos clústeres y permite que el balanceador de carga los trate como un único servicio.

    Puedes consultar los eventos de la pasarela al cabo de unos minutos para ver si se ha terminado de implementar:

    kubectl describe gateway store -n traffic-test --context gke-west-1
    

    El resultado debería ser similar al siguiente:

    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.102.159.147
      Conditions:
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has deprecated this condition, do not depend on it.
        Observed Generation:   1
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Accepted
        Status:                True
        Type:                  Accepted
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Programmed
        Status:                True
        Type:                  Programmed
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
        Observed Generation:   1
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:
          Observed Generation:   1
          Reason:                Programmed
          Status:                True
          Type:                  Programmed
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
          Observed Generation:   1
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
    Events:
      Type    Reason  Age                  From                   Message
      ----    ------  ----                 ----                   -------
      Normal  ADD     12m                  mc-gateway-controller  traffic-test/store
      Normal  SYNC    6m43s                mc-gateway-controller  traffic-test/store
      Normal  UPDATE  5m40s (x4 over 12m)  mc-gateway-controller  traffic-test/store
      Normal  SYNC    118s (x6 over 10m)   mc-gateway-controller  SYNC on traffic-test/store was a success
    

    Este resultado muestra que la pasarela se ha desplegado correctamente. Puede que el tráfico tarde unos minutos en empezar a pasar después de que se haya implementado la pasarela. Anota la dirección IP de este resultado, ya que se usará en un paso posterior.

Confirmar tráfico

Confirma que el tráfico se está enviando a la aplicación probando la dirección IP de la pasarela con un comando curl:

curl GATEWAY_IP_ADDRESS

El resultado debería ser similar al siguiente:

{
  "cluster_name": "gke-west-1",
  "host_header": "34.117.182.69",
  "pod_name": "store-54785664b5-mxstv",
  "pod_name_emoji": "👳🏿",
  "project_id": "project",
  "timestamp": "2021-11-01T14:06:38",
  "zone": "us-west1-a"
}

En este resultado se muestran los metadatos del pod, que indican la región desde la que se ha atendido la solicitud.

Verificar el tráfico mediante pruebas de carga

Para verificar que el balanceador de carga funciona, puedes desplegar un generador de tráfico en tu clúster gke-west-1. El generador de tráfico genera tráfico en diferentes niveles de carga para demostrar la capacidad y las funciones de desbordamiento del balanceador de carga. En los siguientes pasos se muestran tres niveles de carga:

  • 10 RPS, que es inferior a la capacidad del servicio de la tienda en gke-west-1.
  • 30 RPS, que supera la capacidad del servicio de tienda gke-west-1 y provoca un desbordamiento del tráfico a gke-east-1.
  • 60 RPS, que supera la capacidad de los servicios de ambos clústeres.

Configurar el panel de control

  1. Obtén el nombre del mapa de URLs subyacente de tu Gateway:

    kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
    

    El resultado debería ser similar al siguiente:

    /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
    
  2. En la Google Cloud consola, ve a la página Explorador de métricas.

    Ir a Explorador de métricas

  3. En Seleccionar una métrica, haga clic en CÓDIGO: MQL.

  4. Introduce la siguiente consulta para observar las métricas de tráfico del servicio de la tienda en tus dos clústeres:

    fetch https_lb_rule
    | metric 'loadbalancing.googleapis.com/https/backend_request_count'
    | filter (resource.url_map_name == 'GATEWAY_URL_MAP')
    | align rate(1m)
    | every 1m
    | group_by [resource.backend_scope],
        [value_backend_request_count_aggregate:
            aggregate(value.backend_request_count)]
    

    Sustituye GATEWAY_URL_MAP por el nombre de la asignación de URLs del paso anterior.

  5. Haz clic en Realizar una consulta. Espera al menos 5 minutos después de implementar el generador de carga de la siguiente sección para que las métricas se muestren en el gráfico.

Prueba con 10 RPS

  1. Despliega un pod en tu clúster gke-west-1:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 10'
    

    Sustituye GATEWAY_IP_ADDRESS por la dirección IP de la puerta de enlace del paso anterior.

    La salida es similar a la siguiente, lo que indica que el generador de tráfico está enviando tráfico:

    If you don't see a command prompt, try pressing enter.
    

    El generador de carga envía continuamente 10 RPS a la puerta de enlace. Aunque el tráfico proceda de una región de Google Cloud , el balanceador de carga lo trata como tráfico de clientes procedente de la costa oeste de EE. UU. Para simular una diversidad de clientes realista, el generador de carga envía cada solicitud HTTP como una nueva conexión TCP, lo que significa que el tráfico se distribuye de forma más uniforme entre los pods de backend.

    El generador tarda hasta 5 minutos en generar tráfico para el panel de control.

  2. Consulta tu panel de control Explorador de métricas. Aparecen dos líneas que indican la cantidad de tráfico que se balancea de carga en cada uno de los clústeres:

    Gráfico que muestra la carga de tráfico balanceada en los clústeres

    Deberías ver que us-west1-a recibe aproximadamente 10 RPS de tráfico, mientras que us-east1-b no recibe tráfico. Como el generador de tráfico se ejecuta en us-west1, todo el tráfico se envía al servicio del clúster gke-west-1.

  3. Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:

    kubectl delete pod loadgen --context gke-west-1
    

Prueba con 30 RPS

  1. Vuelve a implementar el generador de carga, pero configurado para enviar 30 RPS:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 30'
    

    El generador tarda hasta 5 minutos en generar tráfico para el panel de control.

  2. Consulta tu panel de control de Cloud Ops.

    Gráfico que muestra el tráfico que se desborda a gke-east-1

    Deberías ver que se envían aproximadamente 20 RPS a us-west1-a y 10 RPS a us-east1-b. Esto indica que el servicio de gke-west-1 está totalmente utilizado y que se está transfiriendo un exceso de 10 RPS de tráfico al servicio de gke-east-1.

  3. Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:

    kubectl delete pod loadgen --context gke-west-1
    

Prueba con 60 RPS

  1. Implementa el generador de carga configurado para enviar 60 RPS:

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 60'
    
  2. Espera 5 minutos y consulta tu panel de control de Cloud Ops. Ahora debería mostrar que ambos clústeres reciben aproximadamente 30 RPS. Como todos los servicios están sobreutilizados a nivel mundial, no hay desbordamiento de tráfico y los servicios absorben todo el tráfico que pueden.

    Gráfico que muestra los servicios sobreutilizados

  3. Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:

    kubectl delete pod loadgen --context gke-west-1
    

Limpieza

Después de completar los ejercicios de este documento, siga estos pasos para quitar recursos y evitar que se apliquen cargos no deseados a su cuenta:

  1. Elimina los clústeres.

  2. Anula el registro de los clústeres de la flota si no es necesario que estén registrados para otro propósito.

  3. Para inhabilitar la función multiclusterservicediscovery, sigue estos pasos:

    gcloud container fleet multi-cluster-services disable
    
  4. Inhabilita la entrada de varios clústeres:

    gcloud container fleet ingress disable
    
  5. Inhabilita las APIs:

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

Solución de problemas

No hay upstream en buen estado

Síntoma:

El siguiente problema puede producirse cuando crea una pasarela, pero no puede acceder a los servicios de backend (código de respuesta 503):

no healthy upstream

Motivo:

Este mensaje de error indica que el comprobador de estado no puede encontrar servicios de backend en buen estado. Es posible que tus servicios de backend estén en buen estado, pero que tengas que personalizar las comprobaciones del estado.

Solución alternativa:

Para solucionar este problema, personaliza la comprobación de estado según los requisitos de tu aplicación (por ejemplo, /health) mediante un HealthCheckPolicy.

Siguientes pasos