Usar o proxy Envoy para equilibrar a carga dos serviços gRPC no GKE

Last reviewed 2019-05-30 UTC

Este tutorial demonstra como expor vários serviços gRPC implementados no Google Kubernetes Engine (GKE) num único endereço IP externo através de um equilibrador de carga de rede de encaminhamento direto externo e do Envoy Proxy. O tutorial realça algumas das funcionalidades avançadas que o Envoy oferece para o gRPC.

Introdução

O gRPC é uma framework de RPC de código aberto e independente da linguagem baseada em HTTP/2 que usa memórias intermédias do protocolo para uma representação eficiente na rede e uma serialização rápida. Inspirado no Stubby, a framework de RPCs interna da Google, o gRPC permite uma comunicação de baixa latência entre microsserviços e entre clientes móveis e APIs.

O gRPC é executado através do HTTP/2 e oferece várias vantagens em relação ao HTTP/1.1, como a codificação binária eficiente, a multiplexagem de pedidos e respostas através de uma única ligação e o controlo de fluxo automático. O gRPC também oferece várias opções para o equilíbrio de carga. Este tutorial centra-se em situações em que os clientes não são fidedignos, como clientes móveis e clientes executados fora do limite de confiança do fornecedor de serviços. Das opções de equilíbrio de carga que o gRPC oferece, vai usar o equilíbrio de carga baseado em proxy neste tutorial.

No tutorial, implementa um serviço Kubernetes de TYPE=LoadBalancer, que é exposto como um Network Load Balancer de encaminhamento externo da camada de transporte (camada 4) noGoogle Cloud. Este serviço fornece um único endereço IP público e passa as ligações TCP diretamente para os backends configurados. No tutorial, o back-end é uma implementação do Kubernetes de instâncias do Envoy.

O Envoy é um proxy de camada de aplicação (camada 7) de código aberto que oferece muitas funcionalidades avançadas. Neste tutorial, vai usá-lo para terminar as ligações TLS e encaminhar o tráfego gRPC para o serviço Kubernetes adequado. Em comparação com outras soluções da camada de aplicação, como o Kubernetes Ingress, a utilização do Envoy diretamente oferece várias opções de personalização, como as seguintes:

  • Deteção de serviços
  • Algoritmos de balanceamento de carga
  • Transformar pedidos e respostas, por exemplo, em JSON ou gRPC-Web
  • Autenticar pedidos validando tokens JWT
  • Verificações de funcionamento gRPC

Ao combinar um Network Load Balancer de passagem externo com o Envoy, pode configurar um ponto final (endereço IP externo) que encaminha o tráfego para um conjunto de instâncias do Envoy em execução num cluster do Google Kubernetes Engine. Estas instâncias usam então informações da camada de aplicação para encaminhar pedidos para diferentes serviços gRPC em execução no cluster. As instâncias do Envoy usam o DNS do cluster para identificar e equilibrar a carga dos pedidos gRPC recebidos para os pods em funcionamento e em bom estado de cada serviço. Isto significa que o tráfego é equilibrado para os pods por pedido RPC, em vez de por ligação TCP do cliente.

Arquitetura

Neste tutorial, implementa dois serviços gRPC, echo-grpc e reverse-grpc, num cluster do Google Kubernetes Engine (GKE) e expõe-nos à Internet num endereço IP público. O diagrama seguinte mostra a arquitetura para expor estes dois serviços através de um único ponto final:

arquitetura para expor `echo-grpc` e `reverse-grpc` através de um único ponto final

Um Network Load Balancer de encaminhamento externo aceita pedidos recebidos da Internet (por exemplo, de clientes móveis ou consumidores de serviços fora da sua empresa). O balanceador de carga de rede de encaminhamento externo realiza as seguintes tarefas:

  • Equilibra a carga das ligações recebidas aos nós no conjunto. O tráfego é encaminhado para o serviço do Kubernetes, que é exposto em todos os nós no cluster.envoy O proxy de rede do Kubernetes encaminha estas ligações para pods que estão a executar o Envoy.
  • Realiza verificações de funcionamento de HTTP nos nós no cluster.

O Envoy realiza as seguintes tarefas:

  • Termina as ligações TLS.
  • Descobre pods que executam os serviços gRPC consultando o serviço DNS do cluster interno.
  • Encaminha e equilibra o tráfego para os pods de serviço gRPC.
  • Realiza verificações de funcionamento dos serviços gRPC de acordo com o protocolo de verificação de funcionamento do gRPC.
  • Expõe um ponto final para a verificação de funcionamento das instâncias do Envoy pelo balanceador de carga de rede de encaminhamento externo.

Os serviços gRPC (echo-grpc e reverse-grpc) são expostos como serviços sem cabeça do Kubernetes. Isto significa que não é atribuído nenhum endereço clusterIP e o proxy de rede do Kubernetes não equilibra a carga do tráfego para os pods. Em alternativa, é criado um registo A de DNS que contém os endereços IP do pod no serviço DNS do cluster. O Envoy descobre os endereços IP dos pods a partir desta entrada de DNS e equilibra a carga entre eles de acordo com a política configurada no Envoy.

O diagrama seguinte mostra os objetos do Kubernetes envolvidos neste tutorial:

Objetos do Kubernetes usados neste tutorial, incluindo serviços, ficheiros YAML, registos A de DNS, segredos, pods e entrada de proxy

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

Antes de começar

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    Prepare o ambiente

    1. No Cloud Shell, defina o Google Cloud projeto que quer usar para este tutorial:

      gcloud config set project PROJECT_ID

      Substitua PROJECT_ID pelo ID do seu projeto.Google Cloud

    2. Ative as APIs Artifact Registry e GKE:

      gcloud services enable artifactregistry.googleapis.com \
          container.googleapis.com
      

    Crie o cluster do GKE

    1. No Cloud Shell, crie um cluster do GKE para executar os seus serviços gRPC:

      gcloud container clusters create envoy-grpc-tutorial \
          --enable-ip-alias \
          --release-channel rapid \
          --scopes cloud-platform \
          --workload-pool PROJECT_ID.svc.id.goog \
          --location us-central1-f
      

      Este tutorial usa a zona us-central1-f. Pode usar uma zona ou região diferente.

    2. Verifique se o contexto kubectl foi configurado listando os nós no seu cluster:

      kubectl get nodes --output name
      

      O resultado tem o seguinte aspeto:

      node/gke-envoy-grpc-tutorial-default-pool-c9a3c791-1kpt
      node/gke-envoy-grpc-tutorial-default-pool-c9a3c791-qn92
      node/gke-envoy-grpc-tutorial-default-pool-c9a3c791-wf2h
      

    Crie o repositório do Artifact Registry

    1. No Cloud Shell, crie um novo repositório para armazenar imagens de contentores:

      gcloud artifacts repositories create envoy-grpc-tutorial-images \
          --repository-format docker \
          --location us-central1
      

      Crie o repositório na mesma região que o cluster do GKE para ajudar a otimizar a latência e a largura de banda da rede quando os nós extraem imagens de contentores.

    2. Conceda a função Leitor do Artifact Registry no repositório à conta de serviço Google usada pelas VMs de nós do cluster do GKE:

      PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format 'value(projectNumber)')
      
      gcloud artifacts repositories add-iam-policy-binding envoy-grpc-tutorial-images \
          --location us-central1 \
          --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
          --role roles/artifactregistry.reader
      
    3. Adicione uma entrada de auxiliar de credenciais para o nome de anfitrião do repositório ao ficheiro de configuração do Docker no diretório base do Cloud Shell:

      gcloud auth configure-docker us-central1-docker.pkg.dev
      

      A entrada do auxiliar de credenciais permite que as ferramentas de imagem de contentores executadas no Cloud Shell se autentiquem na localização do repositório do Artifact Registry para extrair e enviar imagens.

    Implemente os serviços gRPC

    Para encaminhar tráfego para vários serviços gRPC atrás de um balanceador de carga, implementa dois serviços gRPC de exemplo: echo-grpc e reverse-grpc. Ambos os serviços expõem um método unário que recebe uma string no campo de pedido content. echo-grpc responde com o conteúdo inalterado, enquanto reverse-grpc responde com a string de conteúdo invertida.

    1. No Cloud Shell, clone o repositório que contém os serviços gRPC e mude para o diretório do repositório:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      cd kubernetes-engine-samples/networking/grpc-gke-nlb-tutorial/
      
    2. Crie um certificado TLS autoassinado e uma chave privada:

      openssl req -x509 -newkey rsa:4096 -nodes -sha256 -days 365 \
          -keyout privkey.pem -out cert.pem -extensions san \
          -config \
          <(echo "[req]";
            echo distinguished_name=req;
            echo "[san]";
            echo subjectAltName=DNS:grpc.example.com
           ) \
          -subj '/CN=grpc.example.com'
      
    3. Crie um segredo do Kubernetes denominado envoy-certs que contenha o certificado TLS autoassinado e a chave privada:

      kubectl create secret tls envoy-certs \
          --key privkey.pem --cert cert.pem \
          --dry-run=client --output yaml | kubectl apply --filename -
      

      O Envoy usa este certificado TLS e chave privada quando termina as ligações TLS.

    4. Crie as imagens de contentores para as apps de exemplo echo-grpc e reverse-grpc, envie as imagens para o Artifact Registry e implemente as apps no cluster do GKE com o Skaffold:

      skaffold run \
          --default-repo=us-central1-docker.pkg.dev/PROJECT_ID/envoy-grpc-tutorial-images \
          --module=echo-grpc,reverse-grpc \
          --skip-tests
      

      O Skaffold é uma ferramenta de código aberto da Google que automatiza os fluxos de trabalho para desenvolver, criar, enviar e implementar aplicações como contentores.

    5. Implemente o Envoy no cluster do GKE através do Skaffold:

      skaffold run \
          --digest-source=none \
          --module=envoy \
          --skip-tests
      
    6. Verifique se existem dois pods prontos para cada implementação:

      kubectl get deployments
      

      O resultado tem um aspeto semelhante ao seguinte. Os valores de READY devem ser 2/2 para todas as implementações.

      NAME           READY   UP-TO-DATE   AVAILABLE   AGE
      echo-grpc      2/2     2            2           1m
      envoy          2/2     2            2           1m
      reverse-grpc   2/2     2            2           1m
      
    7. Verifique se echo-grpc, envoy e reverse-grpc existem como serviços do Kubernetes:

      kubectl get services --selector skaffold.dev/run-id
      

      O resultado tem um aspeto semelhante ao seguinte. Tanto echo-grpc como reverse-grpc devem ter TYPE=ClusterIP e CLUSTER-IP=None.

      NAME           TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)         AGE
      echo-grpc      ClusterIP      None          <none>           8081/TCP        2m
      envoy          LoadBalancer   10.40.2.203   203.0.113.1      443:31516/TCP   2m
      reverse-grpc   ClusterIP      None          <none>           8082/TCP        2m
      

    Teste os serviços gRPC

    Para testar os serviços, use a ferramenta de linha de comandos grpcurl.

    1. No Cloud Shell, instale o grpcurl:

      go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
      
    2. Obtenha o endereço IP externo do serviço Kubernetes e armazene-o numa variável de ambiente:envoy

      EXTERNAL_IP=$(kubectl get service envoy \
          --output=jsonpath='{.status.loadBalancer.ingress[0].ip}')
      
    3. Envie um pedido para a app de exemplo echo-grpc:

      grpcurl -v -d '{"content": "echo"}' \
          -proto echo-grpc/api/echo.proto \
          -authority grpc.example.com -cacert cert.pem \
          $EXTERNAL_IP:443 api.Echo/Echo
      

      O resultado tem o seguinte aspeto:

      Resolved method descriptor:
      rpc Echo ( .api.EchoRequest ) returns ( .api.EchoResponse );
      
      Request metadata to send:
      (empty)
      
      Response headers received:
      content-type: application/grpc
      date: Wed, 02 Jun 2021 07:18:22 GMT
      hostname: echo-grpc-75947768c9-jkdcw
      server: envoy
      x-envoy-upstream-service-time: 3
      
      Response contents:
      {
        "content": "echo"
      }
      
      Response trailers received:
      (empty)
      Sent 1 request and received 1 response
      

      O cabeçalho de resposta hostname mostra o nome do pod echo-grpc que processou o pedido. Se repetir o comando algumas vezes, deve ver dois valores diferentes para o cabeçalho de resposta hostname, correspondentes aos nomes dos pods echo-grpc.

    4. Verifique o mesmo comportamento com o serviço gRPC inverso:

      grpcurl -v -d '{"content": "reverse"}' \
          -proto reverse-grpc/api/reverse.proto \
          -authority grpc.example.com -cacert cert.pem \
          $EXTERNAL_IP:443 api.Reverse/Reverse
      

      O resultado tem o seguinte aspeto:

      Resolved method descriptor:
      rpc Reverse ( .api.ReverseRequest ) returns ( .api.ReverseResponse );
      
      Request metadata to send:
      (empty)
      
      Response headers received:
      content-type: application/grpc
      date: Wed, 02 Jun 2021 07:20:15 GMT
      hostname: reverse-grpc-5c9b974f54-wlfwt
      server: envoy
      x-envoy-upstream-service-time: 1
      
      Response contents:
      {
        "content": "esrever"
      }
      
      Response trailers received:
      (empty)
      Sent 1 request and received 1 response
      

    Configuração do Envoy

    Para compreender melhor a configuração do Envoy, pode consultar o ficheiro de configuração envoy/k8s/envoy.yaml no repositório Git.

    A secção route_config especifica como os pedidos recebidos são encaminhados para as apps de exemplo echo-grpc e reverse-grpc.

    route_config:
      name: local_route
      virtual_hosts:
      - name: local_service
        domains:
        - "*"
        routes:
        - match:
            prefix: "/api.Echo/"
          route:
            cluster: echo-grpc
        - match:
            prefix: "/api.Reverse/"
          route:
            cluster: reverse-grpc

    As apps de exemplo são definidas como clusters do Envoy.

    clusters:
    - name: echo-grpc
      connect_timeout: 0.5s
      type: STRICT_DNS
      dns_lookup_family: V4_ONLY
      lb_policy: ROUND_ROBIN
      http2_protocol_options: {}
      load_assignment:
        cluster_name: echo-grpc
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: echo-grpc.default.svc.cluster.local
                  port_value: 8081
      health_checks:
        timeout: 1s
        interval: 10s
        unhealthy_threshold: 2
        healthy_threshold: 2
        grpc_health_check: {}

    Os campos type: STRICT_DNS e lb_policy: ROUND_ROBIN na definição do cluster especificam que o Envoy realiza procuras de DNS do nome de anfitrião especificado no campo address e equilibra a carga nos endereços IP na resposta à procura de DNS. A resposta contém vários endereços IP porque os objetos de serviço do Kubernetes que definem as apps de exemplo especificam serviços sem cabeçalho.

    O campo http2_protocol_options especifica que o Envoy usa o protocolo HTTP/2 para as apps de exemplo.

    O campo grpc_health_check na secção health_checks especifica que o Envoy usa o protocolo de verificação de funcionamento gRPC para determinar o funcionamento das apps de exemplo.

    Resolver problemas

    Se tiver problemas com este tutorial, recomendamos que reveja estes documentos:

    Também pode explorar a interface de administração do Envoy para diagnosticar problemas com a configuração do Envoy.

    1. Para abrir a interface de administração, configure o encaminhamento de porta do Cloud Shell para a porta admin de um dos pods do Envoy:

      kubectl port-forward \
          $(kubectl get pods -o name | grep envoy | head -n1) 8080:8090
      
    2. Aguarde até ver este resultado na consola:

      Forwarding from 127.0.0.1:8080 -> 8090
      
    3. Clique no botão Pré-visualização na Web no Cloud Shell e selecione Pré-visualizar na porta 8080. Esta ação abre uma nova janela do navegador que mostra a interface de administração.

      Interface de administração do Envoy com a pré-visualização selecionada

    4. Quando terminar, volte ao Cloud Shell e prima Control+C para terminar o encaminhamento de portas.

    Formas alternativas de encaminhar o tráfego gRPC

    Pode modificar esta solução de várias formas para se adequar ao seu ambiente.

    Balanceadores de carga da camada de aplicação alternativos

    Algumas das funcionalidades da camada de aplicação que o Envoy oferece também podem ser oferecidas por outras soluções de equilíbrio de carga:

    • Pode usar um balanceador de carga de aplicações externo global ou um balanceador de carga de aplicações externo regional em vez de um balanceador de carga de rede de encaminhamento externo e um Envoy autogerido. A utilização de um Application Load Balancer externo oferece várias vantagens em comparação com um Network Load Balancer de passagem externo, como a capacidade de gestão de tráfego avançada, certificados TLS geridos e integração com outros Google Cloud produtos, como o Cloud CDN, o Google Cloud Armor e o IAP.

      Recomendamos que use um Application Load Balancer externo global ou um Application Load Balancer externo regional se as capacidades de gestão de tráfego que oferecem satisfizerem os seus exemplos de utilização e se não precisar de suporte para autenticação baseada em certificados de cliente, também conhecida como autenticação TLS mútua (mTLS). Para mais informações, consulte os seguintes documentos:

    • Se usar o Cloud Service Mesh ou o Istio, pode usar as respetivas funcionalidades para encaminhar e equilibrar a carga do tráfego gRPC. Tanto a Cloud Service Mesh como o Istio fornecem um gateway de entrada implementado como um Network Load Balancer de passagem externo com um back-end do Envoy, semelhante à arquitetura neste tutorial. A principal diferença é que o Envoy é configurado através dos objetos de encaminhamento de tráfego do Istio.

      Para tornar os serviços de exemplo neste tutorial encaminháveis na malha de serviços do Google Cloud ou na malha de serviços do Istio, tem de remover a linha clusterIP: None dos manifestos de serviços do Kubernetes (echo-service.yaml e reverse-service.yaml). Isto significa usar a funcionalidade de deteção de serviços e equilíbrio de carga da malha de serviços do Google Cloud ou do Istio em vez da funcionalidade semelhante no Envoy.

      Se já usa o Cloud Service Mesh ou o Istio, recomendamos que use o gateway de entrada para fazer o encaminhamento para os seus serviços gRPC.

    • Pode usar o NGINX em vez do Envoy, como uma implementação ou usando o controlador de entrada NGINX para Kubernetes. O Envoy é usado neste tutorial porque oferece uma funcionalidade gRPC mais avançada, como suporte para o protocolo de verificação do estado do gRPC.

    Conetividade da rede de VPC interna

    Se quiser expor os serviços fora do cluster do GKE, mas apenas na rede VPC, pode usar um Network Load Balancer de encaminhamento interno ou um Application Load Balancer interno.

    Para usar um Network Load Balancer de encaminhamento interno em vez de um Network Load Balancer de encaminhamento externo, adicione a anotação cloud.google.com/load-balancer-type: "Internal" ao manifesto envoy-service.yaml.

    Para usar um balanceador de carga de aplicações interno, consulte a documentação sobre a configuração da entrada para balanceadores de carga de aplicações internos.

    Limpar

    Depois de concluir o tutorial, pode limpar os recursos que criou para que deixem de usar a quota e incorrer em custos. As secções seguintes descrevem como eliminar ou desativar estes recursos.

    Elimine o projeto

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    Elimine os recursos

    Se quiser manter o Google Cloud projeto que usou neste tutorial, elimine os recursos individuais:

    1. No Cloud Shell, elimine o clone do repositório Git local:

      cd ; rm -rf kubernetes-engine-samples/networking/grpc-gke-nlb-tutorial/
      
    2. Elimine o cluster do GKE:

      gcloud container clusters delete envoy-grpc-tutorial \
          --location us-central1-f --async --quiet
      
    3. Elimine o repositório no Artifact Registry:

      gcloud artifacts repositories delete envoy-grpc-tutorial-images \
          --location us-central1 --async --quiet
      

    O que se segue?