Implemente um gateway de vários clusters para a divisão de tráfego ponderada

Este documento explica uma implementação azul-verde de uma aplicação de exemplo em dois clusters do GKE.store As implementações azul-verde são uma estratégia eficaz para migrar as suas aplicações para novos clusters do GKE com um risco mínimo. Ao mudar gradualmente o tráfego do cluster atual (azul) para o novo cluster (verde), pode validar o novo ambiente em produção antes de se comprometer com uma mudança completa.

Os gateways em vários clusters oferecem uma forma eficaz de gerir o tráfego para serviços implementados em vários clusters do GKE. Ao usar a infraestrutura de balanceamento de carga global da Google, pode criar um único ponto de entrada para as suas aplicações, o que simplifica a gestão e melhora a fiabilidade.

Neste tutorial, vai usar uma aplicação de exemplo store para simular um cenário real em que um serviço de compras online é detido e operado por equipas separadas e implementado numa frota de clusters do GKE partilhados.

Antes de começar

Os gateways de vários clusters requerem alguma preparação ambiental antes de poderem ser implementados. Antes de continuar, siga os passos em Prepare o seu ambiente para gateways multicluster:

  1. Implemente clusters do GKE.

  2. Registe os seus clusters numa frota (se ainda não o tiverem feito).

  3. Ative os controladores de serviço em vários clusters e de gateway em vários clusters.

Por último, reveja as limitações e os problemas conhecidos do controlador do GKE Gateway antes de usar o controlador no seu ambiente.

Encaminhamento azul-verde de vários clusters com o Gateway

As GatewayClasses gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* e gke-l7-rilb-* têm muitas capacidades avançadas de encaminhamento de tráfego, incluindo divisão de tráfego, correspondência de cabeçalhos, manipulação de cabeçalhos, espelhamento de tráfego e muito mais. Neste exemplo, vai demonstrar como usar a divisão de tráfego baseada em ponderação para controlar explicitamente a proporção de tráfego em dois clusters do GKE.

Este exemplo aborda alguns passos realistas que um proprietário de um serviço daria para mover ou expandir a respetiva aplicação para um novo cluster do GKE. O objetivo das implementações azul-verde é reduzir o risco através de vários passos de validação que confirmam que o novo cluster está a funcionar corretamente. Este exemplo explica quatro fases de implementação:

  1. 100%-Canário baseado em cabeçalhos: Use o encaminhamento de cabeçalhos HTTP para enviar apenas tráfego de teste ou sintético para o novo cluster.
  2. 100%: refletir tráfego: refletir tráfego de utilizadores para o cluster de teste. Este teste testa a capacidade do cluster de teste preliminar copiando 100% do tráfego de utilizadores para este cluster.
  3. 90%-10%: Teste canário de uma divisão de tráfego de 10% para expor lentamente o novo cluster ao tráfego em direto.
  4. 0%-100%: Transição total para o novo cluster com a opção de reverter se forem observados erros.

Divisão de tráfego azul-verde em dois clusters do GKE

Este exemplo é semelhante ao anterior, exceto que implementa um gateway interno de vários clusters. Isto implementa um Application Load Balancer interno que só é acessível de forma privada a partir da VPC. Vai usar os clusters e a mesma aplicação que implementou nos passos anteriores, exceto que vai implementá-los através de um gateway diferente.

Pré-requisitos

O exemplo seguinte baseia-se em alguns dos passos em Implementar um gateway externo de vários clusters. Certifique-se de que concluiu os seguintes passos antes de avançar com este exemplo:

  1. Prepare o seu ambiente para gateways de vários clusters

  2. Implementar uma aplicação de demonstração

    Este exemplo usa os clusters gke-west-1 e gke-west-2 que já configurou. Estes clusters estão na mesma região porque a gke-l7-rilb-mc GatewayClass é regional e só suporta back-ends de cluster na mesma região.

  3. Implemente o serviço e os ServiceExports necessários em cada cluster. Se implementou Services e ServiceExports do exemplo anterior, já implementou alguns destes.

    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
    

    Implementa um conjunto semelhante de recursos em cada cluster:

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

Configurar uma sub-rede só de proxy

Se ainda não o fez, configure uma sub-rede apenas de proxy para cada região na qual está a implementar gateways internos. Esta sub-rede é usada para fornecer endereços IP internos aos proxies do equilibrador de carga e tem de ser configurada com um --purpose definido apenas como REGIONAL_MANAGED_PROXY.

Tem de criar uma sub-rede apenas de proxy antes de criar gateways que gerem equilibradores de carga de aplicações internos. Cada região de uma rede de nuvem virtual privada (VPC) na qual usa equilibradores de carga de aplicações internos tem de ter uma sub-rede apenas de proxy.

O comando gcloud compute networks subnets create cria uma sub-rede só de proxy.

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

Substitua o seguinte:

  • SUBNET_NAME: o nome da sub-rede só de proxy.
  • REGION: a região da sub-rede só de proxy.
  • VPC_NETWORK_NAME: o nome da rede VPC que contém a sub-rede.
  • CIDR_RANGE: o intervalo de endereços IP principal da sub-rede. Tem de usar uma máscara de sub-rede não superior a /26 para que estejam disponíveis, pelo menos, 64 endereços IP para proxies na região. A máscara de sub-rede recomendada é /23.

Implementar o gateway

O Gateway seguinte é criado a partir da gke-l7-rilb-mc GatewayClass, que é um Gateway interno regional que só pode segmentar clusters do GKE na mesma região.

  1. Aplique o manifesto Gateway seguinte ao cluster de configuração, gke-west-1 neste exemplo:

    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. Valide se o gateway foi iniciado com êxito. Pode filtrar apenas os eventos desta entrada com o seguinte comando:

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

    A implementação do gateway foi bem-sucedida se o resultado for semelhante ao seguinte:

    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
    

Teste com base no cabeçalho

O teste canário baseado em cabeçalhos permite ao proprietário do serviço fazer corresponder o tráfego de teste sintético que não é proveniente de utilizadores reais. Esta é uma forma fácil de validar se o funcionamento em rede básico da aplicação está a funcionar sem expor os utilizadores diretamente.

  1. Aplique o manifesto HTTPRoute seguinte ao cluster de configuração, gke-west-1 neste exemplo:

    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
    

    Uma vez implementado, este HTTPRoute configura o seguinte comportamento de encaminhamento:

    • Os pedidos internos para store.example.internal sem o cabeçalho HTTP env: canary são encaminhados para os pods store no cluster gke-west-1
    • Os pedidos internos para store.example.internal com o cabeçalho HTTP env: canary são encaminhados para os pods store no cluster gke-west-2

    A HTTPRoute permite o encaminhamento para diferentes clusters com base nos cabeçalhos HTTP

    Valide se o HTTPRoute está a funcionar corretamente enviando tráfego para o endereço IP do gateway.

  2. Recupere o endereço IP interno de internal-http.

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

    Substitua VIP nos passos seguintes pelo endereço IP que recebe como resultado.

  3. Envie um pedido ao gateway através do cabeçalho HTTP env: canary. Esta ação confirma que o tráfego está a ser encaminhado para gke-west-2. Use um cliente privado na mesma VPC que os clusters do GKE para confirmar que os pedidos estão a ser encaminhados corretamente. O seguinte comando tem de ser executado numa máquina que tenha acesso privado ao endereço IP do gateway. Caso contrário, não funciona.

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

    O resultado confirma que o pedido foi publicado por um pod do cluster 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"
    }
    

Espelho de trânsito

Esta fase envia tráfego para o cluster pretendido, mas também reflete esse tráfego no cluster de teste.

A utilização da replicação é útil para determinar como a carga de tráfego vai afetar o desempenho da aplicação sem afetar as respostas aos seus clientes de forma alguma. Pode não ser necessário para todos os tipos de implementações, mas pode ser útil quando implementa grandes alterações que podem afetar o desempenho ou o carregamento.

  1. Aplique o manifesto HTTPRoute seguinte ao cluster de configuração, gke-west-1 neste exemplo:

    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. Usando o seu cliente privado, envie um pedido para o internal-http gateway. Use o caminho /mirror para poder identificar exclusivamente este pedido nos registos da aplicação num passo posterior.

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. O resultado confirma que o cliente recebeu uma resposta de um pod no cluster 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"
    }
    

    Isto confirma que o cluster principal está a responder ao tráfego. Ainda tem de confirmar que o cluster para o qual está a migrar está a receber tráfego espelhado.

  4. Verifique os registos de aplicações de um store pod no cluster gke-west-2. Os registos devem confirmar que o pod recebeu tráfego espelhado do equilibrador de carga.

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Este resultado confirma que os pods no cluster gke-west-2 também estão a receber os mesmos pedidos. No entanto, as respetivas respostas a estes pedidos não são enviadas de volta ao cliente. Os endereços IP vistos nos registos são os endereços IP internos do balanceador de carga que estão a comunicar com os seus 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 -
    

Divisão de tráfego

A divisão do tráfego é um dos métodos mais comuns de implementação de novo código ou implementação em novos ambientes de forma segura. O proprietário do serviço define uma percentagem explícita do tráfego que é enviado para os back-ends de teste beta, que é normalmente uma quantidade muito pequena do tráfego geral, para que o sucesso da implementação possa ser determinado com uma quantidade aceitável de risco para os pedidos de utilizadores reais.

A divisão do tráfego com uma minoria do tráfego permite ao proprietário do serviço inspecionar o estado de funcionamento da aplicação e as respostas. Se todos os sinais parecerem em bom estado, podem avançar para a mudança completa.

  1. Aplique o manifesto HTTPRoute seguinte ao cluster de configuração, gke-west-1 neste exemplo:

    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. Usando o seu cliente privado, envie um pedido curl contínuo para o gateway internal- http.

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

    O resultado será semelhante a este, indicando que está a ocorrer uma divisão de tráfego de 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",
    ...
    

Transferência de tráfego

A última fase da migração azul-verde consiste em mudar totalmente para o novo cluster e remover o cluster antigo. Se o proprietário do serviço estivesse a integrar um segundo cluster num cluster existente, este último passo seria diferente, uma vez que o passo final teria tráfego a direcionar-se para ambos os clusters. Nesse cenário, recomenda-se uma única storeServiceImportgke-west-1 que tenha pods dos clusters gke-west-1 e gke-west-2. Isto permite que o balanceador de carga tome a decisão de para onde o tráfego deve ir para uma aplicação ativa-ativa, com base na proximidade, no estado e na capacidade.

  1. Aplique o manifesto HTTPRoute seguinte ao cluster de configuração, gke-west-1 neste exemplo:

    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. Usando o seu cliente privado, envie um pedido curl contínuo para o gateway internal- http.

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

    O resultado será semelhante a este, indicando que todo o tráfego está agora a ser direcionado para gke-west-2.

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

Este passo final conclui uma migração de aplicações azul-verde completa de um cluster do GKE para outro cluster do GKE.

Limpar

Depois de concluir os exercícios neste documento, siga estes passos para remover recursos e evitar a incorrência de cobranças indesejadas na sua conta:

  1. Elimine os clusters.

  2. Anule o registo dos clusters da frota se não precisarem de ser registados para outro fim.

  3. Desative a funcionalidade multiclusterservicediscovery:

    gcloud container fleet multi-cluster-services disable
    
  4. Desative a entrada em vários clusters:

    gcloud container fleet ingress disable
    
  5. Desative as APIs:

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

Resolução de problemas

Não existe um upstream em bom estado

Sintoma:

O seguinte problema pode ocorrer quando cria um gateway, mas não consegue aceder aos serviços de back-end (código de resposta 503):

no healthy upstream

Motivo:

Esta mensagem de erro indica que o verificador de estado de funcionamento não consegue encontrar serviços de back-end em bom estado. É possível que os seus serviços de back-end estejam em bom estado, mas pode ter de personalizar as verificações de funcionamento.

Solução alternativa:

Para resolver este problema, personalize a verificação de estado com base nos requisitos da sua aplicação (por exemplo, /health) através de um HealthCheckPolicy.

O que se segue?