Utilizzo del proxy Envoy per bilanciare il carico dei servizi gRPC su GKE

Last reviewed 2019-05-30 UTC

Questo tutorial mostra come esporre più servizi gRPC di cui è stato eseguito il deployment in Google Kubernetes Engine (GKE) su un singolo indirizzo IP esterno utilizzando un bilanciatore del carico di rete passthrough esterno e un proxy Envoy. Il tutorial evidenzia alcune delle funzionalità avanzate fornite da Envoy per gRPC.

Introduzione

gRPC è un framework RPC open source indipendente dal linguaggio basato su HTTP/2 che utilizza i buffer di protocollo per una rappresentazione efficiente on-the-wire e una serializzazione rapida. Ispirato a Stubby, il framework RPC di Google interno, gRPC consente la comunicazione a bassa latenza tra microservizi e tra client mobili e API.

gRPC viene eseguito su HTTP/2 e offre diversi vantaggi rispetto a HTTP/1.1, come l'efficiente codifica binaria, il multiplexing delle richieste e delle risposte su una singola connessione e il controllo automatico del flusso. gRPC offre inoltre diverse opzioni per il bilanciamento del carico. Questo tutorial è incentrato sulle situazioni in cui i client non sono attendibili, ad esempio client mobile e in esecuzione al di fuori del confine di attendibilità del provider di servizi. Tra le opzioni di bilanciamento del carico fornite da gRPC, in questo tutorial utilizzerai il bilanciamento del carico basato su proxy.

Nel tutorial, eseguirai il deployment di un servizio Kubernetes TYPE=LoadBalancer, esposto come bilanciatore del carico di rete passthrough esterno di livello di trasporto (livello 4) su Google Cloud. Questo servizio fornisce un singolo indirizzo IP pubblico e passa le connessioni TCP direttamente ai backend configurati. Nel tutorial, il backend è un deployment Kubernetes di istanze Envoy.

Envoy è un proxy di livello applicazione open source (livello 7) che offre molte funzionalità avanzate. In questo tutorial, lo userai per terminare le connessioni TLS e instradare il traffico gRPC al servizio Kubernetes appropriato. Rispetto ad altre soluzioni a livello di applicazione, come Kubernetes Ingress, l'uso di Envoy offre direttamente molteplici opzioni di personalizzazione, come di seguito:

  • Service Discovery
  • Algoritmi di bilanciamento del carico
  • Trasformazione di richieste e risposte, ad esempio in JSON o gRPC-Web
  • Autenticazione delle richieste mediante la convalida dei token JWT
  • Controlli di integrità gRPC

Combinando un bilanciatore del carico di rete passthrough esterno con Envoy, puoi configurare un endpoint (indirizzo IP esterno) che inoltra il traffico a una serie di istanze Envoy in esecuzione in un cluster Google Kubernetes Engine. Queste istanze utilizzano quindi le informazioni a livello di applicazione per eseguire il proxy delle richieste a diversi servizi gRPC in esecuzione nel cluster. Le istanze Envoy utilizzano il DNS del cluster per identificare e bilanciare il carico delle richieste gRPC in entrata ai pod in stato integro e in esecuzione per ciascun servizio. Ciò significa che il traffico viene con bilanciamento del carico verso i pod in base alla richiesta RPC, anziché per la connessione TCP dal client.

Architettura

In questo tutorial, eseguirai il deployment di due servizi gRPC, echo-grpc e reverse-grpc, in un cluster Google Kubernetes Engine (GKE) e li esponi su internet su un indirizzo IP pubblico. Il seguente diagramma mostra l'architettura per esporre questi due servizi tramite un singolo endpoint:

architettura per esporre "echo-grpc" e "reverse-grpc" attraverso un singolo endpoint

Un bilanciatore del carico di rete passthrough esterno accetta le richieste in arrivo da internet (ad esempio, da client mobili o consumer di servizi esterni alla tua azienda). Il bilanciatore del carico di rete passthrough esterno esegue le seguenti attività:

  • Bilancia il carico delle connessioni in entrata ai nodi nel pool. Il traffico viene inoltrato al servizio Kubernetes envoy, che è esposto su tutti i nodi del cluster. Il proxy di rete Kubernetes inoltra queste connessioni ai pod su cui è in esecuzione Envoy.
  • Esegue controlli di integrità HTTP sui nodi nel cluster.

Envoy esegue le seguenti attività:

  • Termina le connessioni TLS.
  • Rileva i pod che eseguono i servizi gRPC eseguendo una query al servizio DNS del cluster interno.
  • Instrada e bilancia il carico del traffico verso i pod di servizio gRPC.
  • Esegue i controlli di integrità dei servizi gRPC in base al protocollo per il controllo dell'integrità gRPC.
  • Espone un endpoint per il controllo di integrità delle istanze Envoy tramite il bilanciatore del carico di rete passthrough esterno.

I servizi gRPC (echo-grpc e reverse-grpc) sono esposti come servizi headless di Kubernetes. Ciò significa che nessun indirizzo clusterIP viene assegnato e il proxy di rete Kubernetes non bilancia il carico del traffico verso i pod. Invece, nel servizio DNS del cluster viene creato un record A DNS che contiene gli indirizzi IP dei pod. Envoy rileva gli indirizzi IP dei pod da questa voce DNS e bilancia il carico tra di essi in base al criterio configurato in Envoy.

Il seguente diagramma mostra gli oggetti Kubernetes coinvolti in questo tutorial:

Oggetti Kubernetes utilizzati in questo tutorial, inclusi servizi, file YAML, record A DNS, secret, pod e voce di proxy.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud possono essere idonei a una prova senza costi aggiuntivi.

Una volta completate le attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la pagina Pulizia.

Prima di iniziare

  1. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  2. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  3. Nella console Google Cloud, attiva Cloud Shell.

    Attiva Cloud Shell

prepara l'ambiente

  1. In Cloud Shell, imposta il progetto Google Cloud che vuoi utilizzare per questo tutorial:

    gcloud config set project PROJECT_ID
    

    Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.

  2. Abilita le API Artifact Registry e GKE:

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

Crea il cluster GKE

  1. In Cloud Shell, crea un cluster GKE per l'esecuzione dei servizi gRPC:

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

    Questo tutorial utilizza la zona us-central1-f. Puoi utilizzare una zona o regione diversa.

  2. Verifica che il contesto kubectl sia stato configurato elencando i nodi nel tuo cluster:

    kubectl get nodes --output name
    

    L'output è simile a questo:

    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
    

Crea il repository Artifact Registry

  1. In Cloud Shell, crea un nuovo repository per archiviare le immagini container:

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

    Puoi creare il repository nella stessa regione del cluster GKE per ottimizzare la latenza e la larghezza di banda di rete quando i nodi estraggono le immagini container.

  2. Concedi il ruolo Lettore Artifact Registry nel repository all'account di servizio Google utilizzato dalle VM nodo del cluster 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. Aggiungi una voce dell'helper per le credenziali per il nome host del repository al file di configurazione Docker nella home directory di Cloud Shell:

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

    La voce dell'helper per le credenziali consente agli strumenti per immagini container in esecuzione in Cloud Shell di eseguire l'autenticazione nella posizione del repository Artifact Registry per il pull e il push delle immagini.

esegui il deployment dei servizi gRPC

Per instradare il traffico a più servizi gRPC dietro un bilanciatore del carico, esegui il deployment di due servizi gRPC di esempio: echo-grpc e reverse-grpc. Entrambi i servizi espongono un metodo unario che accetta una stringa nel campo della richiesta content. echo-grpc risponde con i contenuti inalterati, mentre reverse-grpc risponde con la stringa di contenuti invertita.

  1. In Cloud Shell, clona il repository contenente i servizi gRPC e passa alla directory del repository:

    git clone https://github.com/GoogleCloudPlatform/grpc-gke-nlb-tutorial.git ~/grpc-gke-nlb-tutorial
    
    cd ~/grpc-gke-nlb-tutorial
    
  2. Crea un certificato TLS autofirmato e una chiave privata:

    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. Crea un secret di Kubernetes denominato envoy-certs che contiene il certificato TLS autofirmato e la chiave privata:

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

    Envoy utilizza questo certificato TLS e questa chiave privata quando termina le connessioni TLS.

  4. Crea le immagini container per le app di esempio echo-grpc e reverse-grpc, esegui il push delle immagini in Artifact Registry ed esegui il deployment delle app nel cluster GKE utilizzando Skaffold:

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

    Skaffold è uno strumento open source di Google che automatizza i flussi di lavoro per lo sviluppo, la creazione, il push e il deployment di applicazioni come container.

  5. Esegui il deployment di Envoy nel cluster GKE utilizzando Skaffold:

    skaffold run \
        --digest-source=none \
        --module=envoy \
        --skip-tests
    
  6. Verifica che due pod siano pronti per ogni deployment:

    kubectl get deployments
    

    L'output è simile al seguente. I valori di READY devono essere 2/2 per tutti i deployment.

    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. Verifica che echo-grpc, envoy e reverse-grpc esistano come servizi Kubernetes:

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

    L'output è simile al seguente. Sia echo-grpc che reverse-grpc devono avere 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
    

Testa i servizi gRPC

Per testare i servizi, utilizza lo strumento a riga di comando grpcurl.

  1. In Cloud Shell, installa grpcurl:

    go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
    
  2. Recupera l'indirizzo IP esterno del servizio Kubernetes envoy e archivialo in una variabile di ambiente:

    EXTERNAL_IP=$(kubectl get service envoy \
        --output=jsonpath='{.status.loadBalancer.ingress[0].ip}')
    
  3. Invia una richiesta all'app di esempio 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
    

    L'output è simile a questo:

    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
    

    L'intestazione della risposta hostname mostra il nome del pod echo-grpc che ha gestito la richiesta. Se ripeti il comando alcune volte, dovresti vedere due diversi valori per l'intestazione della risposta hostname, corrispondenti ai nomi dei pod echo-grpc.

  4. Verifica lo stesso comportamento con il servizio 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
    

    L'output è simile a questo:

    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
    

Configurazione Envoy

Per comprendere meglio la configurazione Envoy, puoi guardare il file di configurazione envoy/k8s/envoy.yaml nel repository Git.

La sezione route_config specifica in che modo le richieste in entrata vengono instradate alle app di esempio 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

Le app di esempio sono definite come cluster 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: {}

I campi type: STRICT_DNS e lb_policy: ROUND_ROBIN della definizione del cluster specificano che Envoy esegue ricerche DNS del nome host specificato nel campo address e bilancia il carico tra gli indirizzi IP nella risposta alla ricerca DNS. La risposta contiene più indirizzi IP perché gli oggetti dei servizi Kubernetes che definiscono le app di esempio specificano servizi headless.

Il campo http2_protocol_options specifica che Envoy utilizza il protocollo HTTP/2 per le app di esempio.

Il campo grpc_health_check nella sezione health_checks specifica che Envoy utilizza il protocollo del controllo di integrità gRPC per determinare l'integrità delle app di esempio.

Risolvere i problemi

In caso di problemi con questo tutorial, ti consigliamo di consultare questi documenti:

Puoi anche esplorare l'interfaccia di amministrazione di Envoy per diagnosticare i problemi della configurazione Envoy.

  1. Per aprire l'interfaccia di amministrazione, configura il port forwarding da Cloud Shell alla porta admin di uno dei pod Envoy:

    kubectl port-forward \
        $(kubectl get pods -o name | grep envoy | head -n1) 8080:8090
    
  2. Attendi finché non viene visualizzato questo output nella console:

    Forwarding from 127.0.0.1:8080 -> 8090
    
  3. Fai clic sul pulsante Anteprima web in Cloud Shell e seleziona Anteprima sulla porta 8080. Si aprirà una nuova finestra del browser con l'interfaccia di amministrazione.

    Interfaccia di amministrazione di Envoy con anteprima selezionata

  4. Al termine, torna a Cloud Shell e premi Control+C per terminare il port forwarding.

Metodi alternativi per instradare il traffico gRPC

Puoi modificare questa soluzione in diversi modi per adattarla al tuo ambiente.

Bilanciatori del carico alternativi a livello di applicazione

Alcune delle funzionalità a livello di applicazione fornite da Envoy possono essere fornite anche da altre soluzioni di bilanciamento del carico:

  • Puoi utilizzare un Application Load Balancer esterno globale o un Application Load Balancer esterno regionale anziché un bilanciatore del carico di rete passthrough esterno o un Envoy autogestito. L'utilizzo di un bilanciatore del carico delle applicazioni esterno offre diversi vantaggi rispetto a un bilanciatore del carico di rete passthrough esterno, come funzionalità di gestione avanzata del traffico, certificati TLS gestiti e integrazione con altri prodotti Google Cloud come Cloud CDN, Google Cloud Armor e IAP.

    Ti consigliamo di utilizzare un Application Load Balancer esterno globale o un Application Load Balancer esterno regionale se le funzionalità di gestione del traffico che offrono soddisfano i tuoi casi d'uso e se non hai bisogno di supporto per l'autenticazione basata su certificati client, nota anche come autenticazione TLS reciproca (mTLS). Per ulteriori informazioni, consulta i seguenti documenti:

  • Se utilizzi Anthos Service Mesh o Istio, puoi usarne le funzionalità per instradare e bilanciare il carico del traffico gRPC. Sia Anthos Service Mesh che Istio forniscono un gateway in entrata di cui viene eseguito il deployment come bilanciatore del carico di rete passthrough esterno con un backend Envoy, in modo simile all'architettura di questo tutorial. La differenza principale è che Envoy viene configurata tramite gli oggetti di routing del traffico di Istio.

    Per rendere i servizi di esempio in questo tutorial instradabili nel mesh di servizi Anthos o Istio, devi rimuovere la riga clusterIP: None dai manifest del servizio Kubernetes (echo-service.yaml e reverse-service.yaml). Ciò significa utilizzare la funzionalità di Service Discovery e bilanciamento del carico di Anthos Service Mesh o Istio anziché la funzionalità simile di Envoy.

    Se utilizzi già Anthos Service Mesh o Istio, ti consigliamo di utilizzare il gateway in entrata per instradare i servizi gRPC.

  • Puoi utilizzare NGINX al posto di Envoy, come deployment o utilizzando il controller Ingress NGINX per Kubernetes. Envoy viene utilizzato in questo tutorial perché offre funzionalità gRPC più avanzate, come il supporto per il protocollo per il controllo di integrità gRPC.

Connettività di rete VPC interna

Se vuoi esporre i servizi all'esterno del tuo cluster GKE, ma solo all'interno della tua rete VPC, puoi utilizzare un bilanciatore del carico di rete passthrough interno o un bilanciatore del carico delle applicazioni interno.

Per utilizzare un bilanciatore del carico di rete passthrough interno anziché un bilanciatore del carico di rete passthrough esterno, aggiungi l'annotazione cloud.google.com/load-balancer-type: "Internal" al manifest envoy-service.yaml.

Per utilizzare un bilanciatore del carico delle applicazioni interno, consulta la documentazione sulla configurazione di Ingress per bilanciatori del carico delle applicazioni interni.

Esegui la pulizia

Al termine del tutorial, puoi eseguire la pulizia delle risorse che hai creato in modo che smettano di utilizzare la quota e smettano di essere addebitati. Le sezioni seguenti descrivono come eliminare o disattivare queste risorse.

Elimina il progetto

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Elimina le risorse

Se vuoi mantenere il progetto Google Cloud utilizzato in questo tutorial, elimina le singole risorse:

  1. In Cloud Shell, elimina il clone del repository Git locale:

    cd ; rm -rf ~/grpc-gke-nlb-tutorial
    
  2. Elimina il cluster GKE:

    gcloud container clusters delete envoy-grpc-tutorial \
        --zone us-central1-f --async --quiet
    
  3. Elimina il repository in Artifact Registry:

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

Passaggi successivi