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

Este documento orienta você em uma implantação azul-verde de um aplicativo store de exemplo em dois clusters do GKE. As implantações azul-verde são uma estratégia eficaz para migrar seus aplicativos para novos clusters do GKE com risco mínimo. Ao mudar gradualmente o tráfego do cluster atual (azul) para o novo cluster (verde), é possível validar o novo ambiente em produção antes de fazer uma migração completa.

Os gateways de vários clusters oferecem uma maneira eficiente de gerenciar o tráfego de serviços implantados em vários clusters do GKE. Ao usar a infraestrutura global de balanceamento de carga do Google, você pode criar um único ponto de entrada para seus aplicativos, o que simplifica o gerenciamento e melhora a confiabilidade.

Neste tutorial, você usa um aplicativo store de amostra para simular um cenário real em que um serviço de compras on-line é de propriedade e operado por equipes separadas e implantado em uma frota de clusters compartilhados do GKE.

Antes de começar

Os gateways de vários clusters precisam de preparação do ambiente para serem implantados. Antes de continuar, siga as etapas em Preparar o ambiente para gateways de vários clusters:

  1. Implante cluster do GKE.

  2. Registre os clusters em uma frota, se ainda não tiver feito isso.

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

Por fim, analise as limitações e problemas conhecidos do GKE Gateway controller antes de usá-lo no seu ambiente.

Roteamento azul-verde com vários clusters usando o Gateway

O GatewayClasses gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* e gke-l7-rilb-* tem muitos recursos avançados de roteamento de tráfego, incluindo divisão de tráfego, correspondência de cabeçalho, manipulação de cabeçalho, espelhamento de tráfego e muito mais. Neste exemplo, mostraremos como usar a divisão de tráfego baseada em peso para controlar explicitamente a proporção de tráfego em dois clusters do GKE.

Este exemplo mostra algumas etapas realistas que um proprietário de serviço faria ao mover ou expandir o aplicativo para um novo cluster do GKE. O objetivo das implantações azul-verde é reduzir o risco por meio de várias etapas de validação que confirmam se o novo cluster está funcionando corretamente. Este exemplo mostra quatro etapas de implantação:

  1. 100%-Canário baseado em cabeçalho: use o roteamento de cabeçalho HTTP para enviar apenas tráfego de teste ou sintético no novo cluster.
  2. 100%-Espelhar o tráfego: espelha o tráfego de usuários para o cluster canário. Isso testa a capacidade do cluster canário copiando 100% do tráfego do usuário para esse cluster.
  3. 90%-10%: canário de uma divisão de tráfego de 10% para expor lentamente o novo cluster para o tráfego em tempo real.
  4. 0%-100%: mude totalmente para o novo cluster com a opção de reverter se os erros observados.

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

Este exemplo é semelhante ao anterior, mas implanta um gateway interno de vários clusters. Ele implanta um balanceador de carga de aplicativo interno que só pode ser acessado de maneira particular dentro da VPC. Você usará os mesmos clusters e o mesmo aplicativo implantados nas etapas anteriores, mas irá implantá-los em um Gateway diferente.

Pré-requisitos

O exemplo a seguir se baseia em algumas das etapas de Como implantar um gateway externo de vários clusters. Certifique-se de ter concluído as seguintes etapas antes de continuar com este exemplo:

  1. Preparar o ambiente para gateways de vários clusters

  2. Como implantar um aplicativo de demonstração

    Neste exemplo, usamos os clusters gke-west-1 e gke-west-2 que você já configurou. Esses clusters estão na mesma região porque o GatewayClass gke-l7-rilb-mc é regional e só aceita back-ends de cluster na mesma região.

  3. Implantar o Service e o ServiceExports necessários em cada cluster. Se você implantou os Services e ServiceExports do exemplo anterior, então já implantou alguns deles.

    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
    

    Ele implanta 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
    

Como configurar uma sub-rede somente proxy

Se você ainda não tiver feito isso, configure uma sub-rede somente proxy para cada região em que os gateways internos estão sendo implantados. Essa sub-rede é usada para fornecer endereços IP internos aos proxies do balanceador de carga e precisa ser configurada com --purpose definido apenas como REGIONAL_MANAGED_PROXY.

Crie uma sub-rede apenas de proxy antes de criar gateways que gerenciem balanceadores de carga de aplicativo internos. Cada região de uma rede de nuvem privada virtual (VPC) em que você usa balanceadores de carga de aplicativos internos precisa ter uma sub-rede apenas de proxy.

O comando gcloud compute networks subnets create cria uma sub-rede somente proxy.

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

Substitua:

  • SUBNET_NAME: o nome da sub-rede somente proxy.
  • REGION: a região da sub-rede somente 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. Use uma máscara de sub-rede de até /26 de comprimento para que ao menos 64 endereços IP estejam disponíveis para os proxies na região. A máscara de sub-rede recomendada é /23.

Como implantar o gateway

O gateway a seguir é criado com base no GatewayClass gke-l7-rilb-mc, que é um gateway interno regional que só pode segmentar clusters do GKE na mesma região.

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

    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. Confira se o gateway foi criado. É possível filtrar apenas os eventos desse gateway com o seguinte comando:

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

    A implantação do gateway foi bem-sucedida se a saída for semelhante a esta:

    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
    

Canário com base em cabeçalho

O canário baseado em cabeçalho permite que o proprietário do serviço corresponda ao tráfego de teste sintético que não vem de usuários reais. Isso facilita a validação de que a rede básica do aplicativo está funcionando sem expor os usuários diretamente.

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

    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
    

    Depois de implantado, esse HTTPRoute configura o seguinte comportamento de roteamento:

    • Solicitações internas para store.example.internal sem o cabeçalho HTTP env: canary são roteadas para pods store no cluster gke-west-1
    • Solicitações internas para store.example.internal com o cabeçalho HTTP env: canary são roteadas para pods store no cluster gke-west-2

    O HTTPRoute permite o roteamento para clusters diferentes com base nos cabeçalhos HTTP

    Envie tráfego para o endereço IP do gateway para validar o funcionamento correto do HTTPRoute.

  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 nas etapas a seguir pelo endereço IP que você recebe como saída.

  3. Envie uma solicitação para o gateway usando o cabeçalho HTTP env: canary. Isso confirmará que o tráfego está sendo roteado para gke-west-2. Use um cliente particular na mesma VPC que os clusters do GKE para confirmar se as solicitações estão sendo roteadas corretamente. O comando a seguir precisa ser executado em uma máquina que tenha acesso particular ao endereço IP do gateway. Caso contrário, ela não funcionará.

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

    A saída confirma que a solicitação foi exibida 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"
    }
    

Espelhamento do tráfego

Esse estágio envia o tráfego para o cluster pretendido, mas também espelha esse tráfego para o cluster canário.

Usar o espelhamento é útil para determinar como a carga do tráfego afetará o desempenho do aplicativo sem afetar as respostas aos clientes. Talvez não seja necessário para todos os tipos de lançamentos, mas pode ser útil ao implementar grandes alterações que podem afetar o desempenho ou a carga.

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

    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 seu cliente particular, envie uma solicitação para o gateway internal-http. Use o caminho /mirror para identificar exclusivamente essa solicitação nos registros do aplicativo em uma etapa posterior.

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. A resposta 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"
    }
    

    Isso confirma que o cluster principal está respondendo ao tráfego. Você ainda precisa confirmar se o cluster para o qual está migrando está recebendo tráfego espelhado.

  4. Verifique os registros do aplicativo de um pod store no cluster gke-west-2. Os registros precisam confirmar que o pod recebeu tráfego espelhado do balanceador de carga.

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Essa saída confirma que os pods no cluster gke-west-2 também estão recebendo as mesmas solicitações. No entanto, as respostas a essas solicitações não são enviadas de volta ao cliente. Os endereços IP vistos nos registros são os dos endereços IP internos do balanceador de carga que estão se comunicando com 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 de tráfego é um dos métodos mais comuns de lançar novo código ou implantar em novos ambientes com segurança. O proprietário do serviço define uma porcentagem explícita de tráfego enviada para os back-ends canários, que geralmente é uma quantidade muito pequena do tráfego geral. Assim, o sucesso do lançamento pode ser determinado com uma quantidade aceitável de risco para solicitações reais de usuários.

Fazer uma divisão de tráfego com uma minoria de tráfego permite que o proprietário do serviço inspecione a integridade do aplicativo e as respostas. Se todos os sinais parecerem íntegros, eles poderão prosseguir para a transição completa.

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

    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 seu cliente particular, envie uma solicitação curl contínua para o gateway internal- http.

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

    A saída será semelhante a esta, indicando que está ocorrendo 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",
    ...
    

Redução do tráfego

A última etapa da migração azul-verde é totalmente transferida para o novo cluster e remove o antigo. Se o proprietário do serviço estivesse realmente integrando um segundo cluster a um cluster existente, essa última etapa seria diferente, porque a etapa final teria o tráfego fluindo para os dois clusters. Nesse cenário, é recomendado um único ServiceImport store que tenha pods dos clusters gke-west-1 e gke-west-2. Isso permite que o balanceador de carga tome a decisão de onde o tráfego deve ir para um aplicativo ativo-ativo, com base em proximidade, integridade e capacidade.

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

    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 seu cliente particular, envie uma solicitação curl contínua para o gateway internal- http.

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

    A saída será semelhante a esta, indicando que todo o tráfego está indo agora para gke-west-2.

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

Essa etapa final conclui uma migração completa de aplicativos azul-verde de um cluster do GKE para outro cluster do GKE.

Limpar

Depois de concluir os exercícios neste documento, siga estas etapas para remover os recursos e evitar cobranças indesejadas na conta:

  1. Excluir os clusters.

  2. Cancele o registro dos clusters da frota se eles não precisarem ser registrados para outra finalidade.

  3. Desative o recurso multiclusterservicediscovery:

    gcloud container fleet multi-cluster-services disable
    
  4. Desativar a Entrada de 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
    

Solução de problemas

Nenhum upstream íntegro

Sintoma:

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

no healthy upstream

Motivo:

Esta mensagem de erro indica que a sondagem da verificação de integridade não consegue encontrar a integridade dos serviços de back-end. É possível que os serviços de back-end estejam íntegros, mas talvez seja necessário personalizar as verificações de integridade.

Alternativa:

Para resolver esse problema, personalize a verificação de integridade com base nas condições (por exemplo, /health) usando um HealthCheckPolicy.

A seguir