Utilizzo di Envoy Proxy per il bilanciamento del 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 Google Kubernetes Engine (GKE) su un singolo indirizzo IP esterno utilizzando una bilanciatore del carico di rete passthrough esterno e Proxy di 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 buffer di protocollo per una rappresentazione on-the-wire efficiente e una rapida serializzazione. Ispirato a Stubby del framework RPC interno di Google, gRPC consente una bassa latenza la comunicazione tra microservizi e tra client mobile e API.

gRPC viene eseguito su HTTP/2 e offre diversi vantaggi rispetto a HTTP/1.1, quali: codifica binaria efficiente, multiplexing di richieste e risposte su un singolo e controllo automatico del flusso. gRPC offre anche diverse opzioni il bilanciamento del carico. Questo tutorial si concentra sulle situazioni in cui i client non sono attendibili, come i client mobile e i client in esecuzione al di fuori del confine di attendibilità del fornitore di servizi. Tra le opzioni di bilanciamento del carico fornite da gRPC, utilizzerai il bilanciamento del carico basato su proxy in questo tutorial.

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

Envoy è un proxy open source a livello di applicazione (livello 7) che offre molte funzionalità avanzate. In questo tutorial, la utilizzerai per terminare TLS e instradare il traffico gRPC al servizio Kubernetes appropriato. Rispetto ad altre soluzioni a livello di applicazione come Kubernetes Ingress, l'utilizzo di Envoy offre direttamente più opzioni di personalizzazione, ad esempio:

  • Service Discovery
  • Algoritmi di bilanciamento del carico
  • Trasformazione di richieste e risposte, ad esempio in JSON o gRPC-Web
  • Autenticazione delle richieste mediante 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 del 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 in entrata Richieste gRPC ai pod in stato integro e in esecuzione per ciascun servizio. Ciò significa il traffico viene distribuito con bilanciamento del carico ai pod in base a richiesta RPC anziché per TCP di connessione dal client.

Architettura

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

architettura per l'esposizione di "echo-grpc" e "reverse-grpc" tramite un singolo endpoint

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

  • Esegue il bilanciamento del carico delle connessioni in entrata ai nodi del pool. Traffico viene inoltrato al servizio Kubernetes envoy, che è esposto su tutti nodi nel cluster. Il proxy di rete Kubernetes inoltra questi delle connessioni ai pod che eseguono Envoy.
  • Esegue controlli di integrità HTTP sui nodi del cluster.

Envoy esegue le seguenti attività:

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

I servizi gRPC (echo-grpc e reverse-grpc) sono esposti come servizi headless Kubernetes. Ciò significa che non è stato assegnato alcun indirizzo clusterIP e il proxy di rete Kubernetes non esegue il bilanciamento del carico del traffico verso i pod. Al contrario, un record A DNS contiene gli indirizzi IP dei pod creati nel servizio DNS del cluster. Envoy rileva gli indirizzi IP dei pod da questa voce DNS e dai bilanciatori del carico 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 DNS A, secret, pod e voci proxy

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi basata sull'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

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. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

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

    Activate Cloud Shell

prepara l'ambiente

  1. In Cloud Shell, imposta il progetto Google Cloud che da usare per questo tutorial:

    gcloud config set project PROJECT_ID

    Sostituisci PROJECT_ID con il tuo ID 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 eseguire i tuoi 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 un'altra zona o regione.

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

    kubectl get nodes --output name
    

    L'output è simile al seguente:

    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 in cui archiviare le immagini container:

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

    Il repository viene creato nella stessa regione di GKE per ottimizzare la latenza e la larghezza di banda della rete quando i nodi eseguono il pull immagini container.

  2. Concedi Lettore Artifact Registry del repository all'account di servizio Google utilizzato dalle VM del 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 di helper delle 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 di utilità per le credenziali consente agli strumenti per le immagini dei container in esecuzione in Cloud Shell di autenticarsi 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 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 invariati, 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/kubernetes-engine-samples
    cd kubernetes-engine-samples/networking/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 segreto Kubernetes denominato envoy-certs che contenga 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 TLS e connessioni a Internet.

  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 al 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 delle 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 per 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 Kubernetes Servizi:

    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 grpcurl a strumento a riga di comando.

  1. In Cloud Shell, installa grpcurl:

    go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
    
  2. Ottieni 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 al seguente:

    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 valori diversi per l'intestazione di 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 al seguente:

    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 di Envoy, puoi esaminare 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 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 Cluster di 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 nella definizione del cluster specificano che Envoy esegue ricerche DNS del nome host specificato nel campo address e il bilanciamento del carico tra gli indirizzi IP nella risposta alla ricerca DNS. La risposta contiene più indirizzi IP perché gli oggetti Kubernetes Service 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 per il controllo di integrità gRPC per determinare l'integrità del app di esempio.

Risoluzione dei problemi

Se riscontri problemi con questo tutorial, ti consigliamo di esaminare i seguenti documenti:

Puoi anche esplorare l'interfaccia di amministrazione di Envoy per diagnosticare i problemi relativi alla configurazione di 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. Viene visualizzata una nuova finestra del browser in cui a riga di comando gcloud.

    Interfaccia di amministrazione di Envoy con l&#39;anteprima selezionata

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

Metodi alternativi per instradare il traffico gRPC

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

Bilanciatori del carico a livello di applicazione alternativi

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

  • Puoi utilizzare uno dei seguenti Bilanciatore del carico delle applicazioni esterno globale o bilanciatore del carico delle applicazioni esterno regionale invece di un bilanciatore del carico di rete passthrough esterno e di Envoy autogestito. L'utilizzo di un il bilanciatore del carico delle applicazioni esterno offre diversi vantaggi rispetto a un bilanciatore del carico di rete passthrough esterno, come funzionalità avanzate di gestione del traffico, certificati TLS gestiti, e l'integrazione con altri prodotti Google Cloud come Cloud CDN, Google Cloud Armor e IAP.

    Ti consigliamo di utilizzare un bilanciatore del carico delle applicazioni esterno globale oppure Bilanciatore del carico delle applicazioni esterno regionale se offre funzionalità di gestione del traffico soddisfare i tuoi casi d'uso e se non hai bisogno di assistenza per autenticazione basata su certificati, nota anche come TLS reciproca (mTLS) autenticazione. Per ulteriori informazioni, consulta i seguenti documenti:

  • Se utilizzi Cloud Service Mesh o Istio, puoi utilizzare le relative funzionalità per instradare e bilanciare il carico del traffico gRPC. Sia Cloud Service Mesh che Istio forniscono Gateway in entrata distribuito come bilanciatore del carico di rete passthrough esterno con un backend Envoy, all'architettura. La differenza principale è che Envoy viene configurato tramite il protocollo instradamento del traffico di oggetti strutturati.

    Come rendere instradabili i servizi di esempio di questo tutorial in Cloud Service Mesh o il mesh di servizi Istio, devi rimuovere la riga clusterIP: None dal Manifest dei servizi Kubernetes (echo-service.yaml e reverse-service.yaml). Ciò significa utilizzare il Service Discovery e caricamento funzionalità di bilanciamento di Cloud Service Mesh o Istio anziché le sue funzionalità in Envoy.

    Se utilizzi già Cloud Service Mesh o Istio, ti consigliamo di utilizzare il gateway di ingresso per eseguire il routing ai tuoi servizi gRPC.

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

Connettività di rete VPC interna

Se vuoi esporre i servizi all'esterno del cluster GKE, solo all'interno della tua rete VPC, puoi utilizzare 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 al posto di 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 i bilanciatori del carico delle applicazioni interni.

Esegui la pulizia

Al termine del tutorial, puoi eliminare le risorse che hai creato in modo che smettano di utilizzare la quota e di generare addebiti. Le seguenti sezioni descrivono come eliminare o disattivare queste risorse.

Elimina il progetto

  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.

Elimina le risorse

Se vuoi conservare il progetto Google Cloud che hai usato in questo tutorial, elimina le singole risorse:

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

    cd ; rm -rf kubernetes-engine-samples/networking/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