Desplegar una pasarela de varios clústeres para dividir el tráfico ponderado

En este documento se explica cómo realizar un despliegue azul-verde de una aplicación de ejemplo store en dos clústeres de GKE. Las implementaciones azul-verde son una estrategia eficaz para migrar tus aplicaciones a nuevos clústeres de GKE con un riesgo mínimo. Si transfieres el tráfico gradualmente del clúster actual (azul) al nuevo (verde), puedes validar el nuevo entorno en producción antes de completar el cambio.

Las pasarelas de varios clústeres ofrecen una forma eficaz de gestionar el tráfico de los servicios desplegados en varios clústeres de GKE. Si usas la infraestructura de balanceo de carga global de Google, puedes crear un único punto de entrada para tus aplicaciones, lo que simplifica la gestión y mejora la fiabilidad.

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.

Enrutamiento multiclúster azul-verde con Gateway

Las GatewayClasses gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* y gke-l7-rilb-* tienen muchas funciones avanzadas de enrutamiento del tráfico, como la división del tráfico, la coincidencia de encabezados, la manipulación de encabezados, la creación de reflejos del tráfico y más. En este ejemplo, se muestra cómo usar la división del tráfico basada en el peso para controlar explícitamente la proporción del tráfico entre dos clústeres de GKE.

En este ejemplo se describen algunos pasos realistas que seguiría un propietario de un servicio para mover o ampliar su aplicación a un nuevo clúster de GKE. El objetivo de los despliegues azul-verde es reducir los riesgos mediante varios pasos de validación que confirmen que el nuevo clúster funciona correctamente. En este ejemplo se muestran cuatro fases de implementación:

  1. 100%-Canario basado en encabezados: Usa el enrutamiento de encabezados HTTP para enviar solo tráfico de prueba o sintético al nuevo clúster.
  2. 100%: duplica el tráfico: duplica el tráfico de usuarios al clúster canary. De esta forma, se prueba la capacidad del clúster canary copiando el 100% del tráfico de usuarios a este clúster.
  3. 90%-10%: Canary a traffic split del 10% para exponer lentamente el nuevo clúster al tráfico real.
  4. 0%-100%: Cambia por completo al nuevo clúster con la opción de volver al anterior si se detecta algún error.

División del tráfico azul-verde en dos clústeres de GKE

Este ejemplo es similar al anterior, pero en él se implementa una pasarela interna multiclúster. De esta forma, se implementa un balanceador de carga de aplicación interno al que solo se puede acceder de forma privada desde la VPC. Usarás los clústeres y la misma aplicación que has implementado en los pasos anteriores, pero los implementarás a través de otra pasarela.

Requisitos previos

En el siguiente ejemplo se siguen algunos de los pasos que se indican en el artículo Desplegar una pasarela externa de varios clústeres. Asegúrate de que has seguido estos pasos antes de continuar con este ejemplo:

  1. Preparar el entorno para las pasarelas de varios clústeres

  2. Desplegar una aplicación de demostración

    En este ejemplo se usan los clústeres gke-west-1 y gke-west-2 que ya has configurado. Estos clústeres están en la misma región porque gke-l7-rilb-mc GatewayClass es regional y solo admite back-ends de clúster en la misma región.

  3. Despliega los servicios y ServiceExports necesarios en cada clúster. Si has implementado los servicios y las exportaciones de servicios del ejemplo anterior, ya habrás implementado algunos de estos.

    kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-1-service.yaml
    kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-2-service.yaml
    

    Despliega un conjunto de recursos similar en cada clúster:

    service/store created
    serviceexport.net.gke.io/store created
    service/store-west-2 created
    serviceexport.net.gke.io/store-west-2 created
    

Configurar una subred de solo proxy

Si aún no lo ha hecho, configure una subred solo de proxy para cada región en la que vaya a implementar pasarelas internas. Esta subred se usa para proporcionar direcciones IP internas a los proxies del balanceador de carga y debe configurarse con un --purpose definido como REGIONAL_MANAGED_PROXY.

Debes crear una subred de solo proxy antes de crear las pasarelas que gestionan los balanceadores de carga de aplicaciones internos. Cada región de una red de nube privada virtual (VPC) en la que uses balanceadores de carga de aplicaciones internos debe tener una subred solo proxy.

El comando gcloud compute networks subnets create 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

Haz los cambios siguientes:

  • 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 intervalo de direcciones IP principal de la subred. Debes usar una máscara de subred que no sea superior a /26 para que haya al menos 64 direcciones IP disponibles para los proxies de la región. La máscara de subred recomendada es /23.

Desplegar la pasarela

La siguiente pasarela se crea a partir de gke-l7-rilb-mc GatewayClass, que es una pasarela interna regional que solo puede dirigirse a clústeres de GKE de la misma región.

  1. 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: internal-http
      namespace: store
    spec:
      gatewayClassName: gke-l7-rilb-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    
  2. Valida que la pasarela se ha iniciado correctamente. Puedes filtrar solo los eventos de esta pasarela con el siguiente comando:

    kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
    

    El despliegue de la pasarela se habrá realizado correctamente si el resultado es similar al siguiente:

    LAST SEEN   TYPE     REASON   OBJECT                  MESSAGE
    5m18s       Normal   ADD      gateway/internal-http   store/internal-http
    3m44s       Normal   UPDATE   gateway/internal-http   store/internal-http
    3m9s        Normal   SYNC     gateway/internal-http   SYNC on store/internal-http was a success
    

Canary basado en encabezados

El lanzamiento de versiones canary basado en encabezados permite al propietario del servicio hacer coincidir el tráfico de prueba sintético que no procede de usuarios reales. Es una forma sencilla de validar que la red básica de la aplicación funciona sin exponer a los usuarios directamente.

  1. 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: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      # Matches for env=canary and sends it to store-west-2 ServiceImport
      - matches:
        - headers:
          - name: env
            value: canary
        backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: store-west-2
            port: 8080
      # All other traffic goes to store-west-1 ServiceImport
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-west-1
          port: 8080
    EOF
    

    Una vez implementado, este HTTPRoute configura el siguiente comportamiento de enrutamiento:

    • Las solicitudes internas a store.example.internal sin el encabezado HTTP env: canary se dirigen a los pods store del clúster gke-west-1.
    • Las solicitudes internas a store.example.internal con el encabezado HTTP env: canary se dirigen a los pods store del clúster gke-west-2.

    HTTPRoute permite enrutar a diferentes clústeres en función de los encabezados HTTP.

    Valida que HTTPRoute funciona correctamente enviando tráfico a la dirección IP de Gateway.

  2. Recupera la dirección IP interna de internal-http.

    kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
    

    Sustituye VIP en los pasos siguientes por la dirección IP que recibas como resultado.

  3. Envía una solicitud a la pasarela mediante el encabezado HTTP env: canary. De esta forma, se confirmará que el tráfico se está enrutando a gke-west-2. Usa un cliente privado en la misma VPC que los clústeres de GKE para confirmar que las solicitudes se enrutan correctamente. El siguiente comando debe ejecutarse en una máquina que tenga acceso privado a la dirección IP de la puerta de enlace. De lo contrario, no funcionará.

    curl -H "host: store.example.internal" -H "env: canary" http://VIP
    

    El resultado confirma que la solicitud la ha atendido un pod del clúster gke-west-2:

    {
        "cluster_name": "gke-west-2", 
        "host_header": "store.example.internal",
        "node_name": "gke-gke-west-2-default-pool-4cde1f72-m82p.c.agmsb-k8s.internal",
        "pod_name": "store-5f5b954888-9kdb5",
        "pod_name_emoji": "😂",
        "project_id": "agmsb-k8s",
        "timestamp": "2021-05-31T01:21:55",
        "zone": "us-west1-a"
    }
    

Duplicación del tráfico

En esta fase, se envía tráfico al clúster de destino, pero también se refleja en el clúster canary.

La función de creación de reflejos es útil para determinar cómo afectará la carga de tráfico al rendimiento de la aplicación sin influir en las respuestas a tus clientes. Puede que no sea necesario para todos los tipos de lanzamientos, pero puede ser útil cuando se lancen cambios importantes que puedan afectar al rendimiento o a la carga.

  1. 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: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      # Sends all traffic to store-west-1 ServiceImport
      - backendRefs:
        - name: store-west-1
          group: net.gke.io
          kind: ServiceImport
          port: 8080
        # Also mirrors all traffic to store-west-2 ServiceImport
        filters:
        - type: RequestMirror
          requestMirror:
            backendRef:
              group: net.gke.io
              kind: ServiceImport
              name: store-west-2
              port: 8080
    EOF
    
  2. Con tu cliente privado, envía una solicitud a la pasarela internal-http. Usa la ruta /mirror para identificar de forma única esta solicitud en los registros de la aplicación en un paso posterior.

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. El resultado confirma que el cliente ha recibido una respuesta de un pod del clúster gke-west-1:

    {
        "cluster_name": "gke-west-1", 
        "host_header": "store.example.internal",
        "node_name": "gke-gke-west-1-default-pool-65059399-ssfq.c.agmsb-k8s.internal",
        "pod_name": "store-5f5b954888-brg5w",
        "pod_name_emoji": "🎖",
        "project_id": "agmsb-k8s",
        "timestamp": "2021-05-31T01:24:51",
        "zone": "us-west1-a"
    }
    

    De esta forma, se confirma que el clúster principal responde al tráfico. Aún debe confirmar que el clúster al que está migrando recibe tráfico reflejado.

  4. Consulta los registros de aplicaciones de un pod store en el clúster gke-west-2. Los registros deberían confirmar que el pod ha recibido tráfico reflejado del balanceador de carga.

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Esta salida confirma que los pods del clúster gke-west-2 también reciben las mismas solicitudes, pero sus respuestas a estas solicitudes no se envían al cliente. Las direcciones IP que se ven en los registros son las direcciones IP internas del balanceador de carga, que se comunican con tus pods.

    Found 2 pods, using pod/store-5c65bdf74f-vpqbs
    [2023-10-12 21:05:20,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:20] "GET /mirror HTTP/1.1" 200 -
    [2023-10-12 21:05:27,158] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
    [2023-10-12 21:05:27,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
    

División del tráfico

La división del tráfico es uno de los métodos más habituales para implementar código nuevo o en entornos nuevos de forma segura. El propietario del servicio define un porcentaje explícito del tráfico que se envía a los backends de lanzamiento de versiones canary, que suele ser una cantidad muy pequeña del tráfico total, de modo que el éxito del lanzamiento se pueda determinar con un riesgo aceptable para las solicitudes de usuarios reales.

Al dividir el tráfico con una minoría del tráfico, el propietario del servicio puede inspeccionar el estado de la aplicación y las respuestas. Si todas las señales parecen correctas, pueden proceder al cambio completo.

  1. 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: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
      - backendRefs:
        # 90% of traffic to store-west-1 ServiceImport
        - name: store-west-1
          group: net.gke.io
          kind: ServiceImport
          port: 8080
          weight: 90
        # 10% of traffic to store-west-2 ServiceImport
        - name: store-west-2
          group: net.gke.io
          kind: ServiceImport
          port: 8080
          weight: 10
    EOF
    
  2. Con tu cliente privado, envía una solicitud curl continua a la internal- http Gateway.

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    El resultado será similar a este, lo que indica que se está produciendo una división del tráfico del 90/10.

    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-1",
    "cluster_name": "gke-west-1",
    ...
    

Cambio de tráfico

La última fase de la migración azul-verde consiste en cambiar por completo al nuevo clúster y eliminar el antiguo. Si el propietario del servicio estuviera incorporando un segundo clúster a un clúster ya creado, este último paso sería diferente, ya que el tráfico se dirigiría a ambos clústeres. En ese caso, se recomienda un único store ServiceImport que tenga pods de los clústeres gke-west-1 y gke-west-2. De esta forma, el balanceador de carga puede decidir a dónde debe dirigirse el tráfico de una aplicación activa-activa en función de la proximidad, el estado y la capacidad.

  1. 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: internal-store-route
      namespace: store
      labels:
        gateway: internal-http
    spec:
      parentRefs:
      - kind: Gateway
        namespace: store
        name: internal-http
      hostnames:
      - "store.example.internal"
      rules:
        - backendRefs:
          # No traffic to the store-west-1 ServiceImport
          - name: store-west-1
            group: net.gke.io
            kind: ServiceImport
            port: 8080
            weight: 0
          # All traffic to the store-west-2 ServiceImport
          - name: store-west-2
            group: net.gke.io
            kind: ServiceImport
            port: 8080
            weight: 100
    EOF
    
  2. Con tu cliente privado, envía una solicitud curl continua a la internal- http Gateway.

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    El resultado será similar a este, lo que indica que todo el tráfico ahora se dirige a gke-west-2.

    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    ...
    

Con este último paso, se completa una migración de aplicaciones azul-verde de un clúster de GKE a otro.

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