Utiliser Istio pour équilibrer la charge des services gRPC internes

Ce tutoriel explique comment configurer l'équilibrage de charge TCP/UDP interne à l'aide d'Istio pour les services gRPC exécutés sur Google Kubernetes Engine (GKE). Cette configuration permet aux autres ressources de votre réseau VPC de communiquer avec les services gRPC via une adresse IP privée interne (RFC 1918). De son côté, Istio s'occupe des requêtes de routage et d'équilibrage de charge sur les pods Kubernetes exécutant les services gRPC.

Dans ce tutoriel, nous partons du principe que vous possédez des connaissances de base sur gRPC, et GKE ou Kubernetes.

Présentation

Istio fournit des passerelles pour la gestion du trafic qui entre dans le maillage de services et qui en sort. La passerelle d'équilibeur de charge interne (ILB, Internal Load Balancer) d'Istio achemine le trafic entrant des sources du réseau VPC interne vers les pods Kubernetes du maillage de services. Dans cette architecture, l'équilibrage de charge TCP/UDP interne de Google Cloud effectue l'équilibrage de charge de couche 4 (couche de transport) sur les nœuds du cluster GKE. La passerelle ILB d'Istio reçoit le trafic et effectue l'équilibrage de charge de couche 7 (couche d'application), en répartissant le trafic entre les services du maillage de services Istio à l'aide des règles définies dans les services virtuels et les règles de destination.

L'exemple de service gRPC utilisé dans ce tutoriel renvoie un en-tête de réponse qui contient le nom du pod Kubernetes qui a traité la requête. Grâce à cette information, vous pouvez voir que l'équilibrage de charge exécuté par la passerelle ILB d'Istio répartit les requêtes effectuées par un client via une seule connexion entre plusieurs pods Kubernetes du cluster GKE.

Objectifs

  • Créer un cluster GKE avec Istio et la passerelle ILB d'Istio
  • Déployer un exemple de service gRPC
  • Vérifier la connectivité interne

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé ce tutoriel, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Consultez la page Effectuer un nettoyage pour en savoir plus.

Avant de commencer

  1. Connectez-vous à votre compte Google ou, si vous n'en avez pas, créez-en un.
  2. Dans Cloud Console, accédez à la page de sélection du projet.

    Accéder à la page de sélection du projet

  3. Sélectionnez ou créez un projet Cloud.

  4. Vérifiez que la facturation est activée pour votre projet Google Cloud. Découvrez comment vérifier que la facturation est activée pour votre projet.

Initialiser l'environnement

  1. Dans le menu déroulant Sélectionner un projet de Cloud Console, sélectionnez le projet que vous souhaitez utiliser.

  2. Ouvrez Cloud Shell.

    Accéder à Cloud Shell

    Utilisez Cloud Shell pour exécuter toutes les commandes de ce tutoriel.

  3. Activez l'API Cloud Build, l'API Google Kubernetes Engine, l'API Container Analysis et les API Cloud :

    gcloud services enable \
        cloudapis.googleapis.com \
        cloudbuild.googleapis.com \
        container.googleapis.com \
        containeranalysis.googleapis.com
    
  4. Définissez la valeur par défaut gcloud de la zone Compute Engine que vous souhaitez utiliser dans ce tutoriel :

    gcloud config set compute/zone us-central1-b
    

    Ce tutoriel utilise la zone us-central1-b. Vous pouvez modifier la zone selon vos besoins.

  5. Clonez le dépôt Git contenant l'exemple de service gRPC et basculez vers le répertoire de travail :

    git clone https://github.com/GoogleCloudPlatform/istio-samples.git
    cd istio-samples/sample-apps/grpc-greeter-go
    

Créer un cluster GKE avec Istio

  1. Dans Cloud Shell, créez un cluster GKE :

    gcloud beta container clusters create grpc-istio-ilb-tutorial \
        --machine-type n1-standard-2 \
        --enable-ip-alias
    
  2. Accordez-vous des droits d'administrateur pour le cluster :

    kubectl create clusterrolebinding cluster-admin-binding \
        --clusterrole cluster-admin \
        --user $(gcloud config get-value account)
    

    Pour pouvoir installer Istio, vous devez disposer des autorisations définies dans le rôle de cluster Kubernetes cluster-admin.

  3. Créez un espace de noms Kubernetes nommé istio-system :

    kubectl create namespace istio-system
    
  4. Téléchargez et extrayez Istio :

    ISTIO_VERSION=1.2.7
    curl -L https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-linux.tar.gz | tar -zxf -
    
  5. Utilisez le rendu de modèle local de Helm pour installer les définitions de ressources personnalisées (CRD, Custom Resource Definition) d'Istio :

    helm template \
        istio-$ISTIO_VERSION/install/kubernetes/helm/istio-init \
        --namespace istio-system | kubectl apply -f -
    
  6. Installez Istio avec la passerelle ILB (istio-ilbgateway) à l'aide de Helm :

    ISTIO_PACKAGE=$ISTIO_VERSION-gke.0
    
    helm template \
        istio-$ISTIO_VERSION/install/kubernetes/helm/istio \
        --set gateways.istio-ingressgateway.enabled=false \
        --set gateways.istio-ilbgateway.enabled=true \
        --set gateways.istio-ilbgateway.ports[0].name=grpc-pilot-mtls \
        --set gateways.istio-ilbgateway.ports[0].port=15011 \
        --set gateways.istio-ilbgateway.ports[1].name=grpc \
        --set gateways.istio-ilbgateway.ports[1].port=443 \
        --set gateways.istio-ilbgateway.ports[2].name=tcp-citadel-grpc-tls \
        --set gateways.istio-ilbgateway.ports[2].port=8060 \
        --set gateways.istio-ilbgateway.ports[2].targetPort=8060 \
        --set gateways.istio-ilbgateway.ports[3].name=tcp-dns \
        --set gateways.istio-ilbgateway.ports[3].port=5353 \
        --set global.hub=gcr.io/gke-release/istio \
        --set global.tag=$ISTIO_PACKAGE \
        --namespace istio-system | kubectl apply -f -
    
  7. Vérifiez l'état de la création d'une adresse IP externe pour le service Kubernetes istio-ilbgateway :

    kubectl get services istio-ilbgateway -n istio-system --watch
    

    Attendez que la valeur EXTERNAL-IP passe de <pending> à une adresse IP. Appuyez sur Control+C pour interrompre l'opération.

Créer un certificat TLS pour la passerelle ILB d'Istio

  1. Dans Cloud Shell, créez un certificat TLS et une clé privée pour autoriser la terminaison TLS par la passerelle ILB d'Istio :

    openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
        -keyout privkey.pem -out cert.pem -subj "/CN=grpc.example.com"
    
  2. Créez un secret Kubernetes pour stocker le certificat TLS et la clé privée :

    kubectl -n istio-system create secret tls istio-ilbgateway-certs \
        --key privkey.pem --cert cert.pem \
        --dry-run -o yaml | kubectl apply -f -
    

Installer l'exemple d'application

L'étape suivante consiste à créer une image de conteneur pour l'exemple de service gRPC et à la déployer sur votre cluster GKE. L'exemple de service gRPC comprend un composant client, appelé client gRPC, et un composant serveur, appelé serveur gRPC.

  1. Dans Cloud Shell, activez l'injection automatique du fichier side-car Istio dans l'espace de noms default :

    kubectl label namespace default istio-injection=enabled
    
  2. Utilisez Cloud Build afin de créer une image de conteneur pour le serveur gRPC :

    gcloud builds submit server -t gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-server
    
  3. Créez les objets Déploiement et Service Kubernetes pour le serveur gRPC :

    envsubst < manifests/greeter-k8s.template.yaml | kubectl apply -f -
    
  4. Vérifiez que le service Kubernetes ClusterIP a bien été créé et que les pods sont en cours d'exécution :

    kubectl get services,pods
    

    Le résultat ressemble à ceci :

    NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    service/greeter      ClusterIP   10.0.18.67   <none>        8080/TCP   11s
    service/kubernetes   ClusterIP   10.0.16.1    <none>        443/TCP    1h
    NAME READY STATUS RESTARTS AGE pod/greeter-844cffd75-7hpcb 2/2 Running 0 56s pod/greeter-844cffd75-ffccl 2/2 Running 0 56s pod/greeter-844cffd75-zww6h 2/2 Running 0 56s

    Les pods affichent 2/2 dans la colonne READY. Ce résultat signifie que pour chaque pod, le conteneur de serveur gRPC et le conteneur side-car Envoy sont en cours d'exécution.

  5. Créez les objets de passerelle, de service virtuel et de règle de destination Istio pour le serveur gRPC :

    kubectl apply -f manifests/greeter-istio-ilbgateway.yaml \
        -f manifests/greeter-istio-virtualservice.yaml \
        -f manifests/greeter-istio-destinationrule.yaml
    
  6. Vérifiez que les trois objets ont bien été créés :

    kubectl get gateway,virtualservice,destinationrule
    

    Le résultat ressemble à ceci :

    NAME                                  AGE
    gateway.networking.istio.io/greeter   1m
    NAME GATEWAYS HOSTS AGE virtualservice.networking.istio.io/greeter [greeter] [*] 1m
    NAME HOST AGE destinationrule.networking.istio.io/greeter greeter 1m

Vérifier la connectivité interne

L'équilibrage de charge TCP/UDP interne étant régional, vous pouvez tester la connectivité à partir d'une VM de la même zone ou région.

  1. Dans Cloud Shell, utilisez Cloud Build afin de créer une image de conteneur pour le client gRPC :

    gcloud builds submit client \
        -t gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client
    
  2. Créez une instance Compute Engine dans la même zone ou région que le cluster GKE :

    gcloud compute instances create grpc-istio-ilb-tutorial-client-vm \
        --scopes https://www.googleapis.com/auth/devstorage.read_only \
        --image-project cos-cloud \
        --image-family cos-stable
    

    Le champ d'application devstorage.read_only est requis pour télécharger des images à partir de Container Registry.

  3. Stockez l'adresse IP de la passerelle ILB d'Istio dans un fichier nommé ilb-ip.txt :

    kubectl -n istio-system get services istio-ilbgateway \
        -o jsonpath='{.status.loadBalancer.ingress[0].ip}' > ilb-ip.txt
    
  4. Copiez le certificat TLS autosigné et le fichier contenant l'adresse IP de la passerelle ILB d'Istio sur la VM :

    gcloud compute scp cert.pem ilb-ip.txt grpc-istio-ilb-tutorial-client-vm:~
    
    
  5. Utilisez SSH pour vous connecter à la VM.

    gcloud compute ssh grpc-istio-ilb-tutorial-client-vm
    
  6. Sur la VM, demandez l'ID du projet au serveur de métadonnées Compute Engine et stockez-le dans la variable d'environnement GOOGLE_CLOUD_PROJECT.

    GOOGLE_CLOUD_PROJECT=$(curl -sH "Metadata-Flavor: Google" \
        http://metadata.google.internal/computeMetadata/v1/project/project-id)
    

    Dans Cloud Shell, la variable d'environnement GOOGLE_CLOUD_PROJECT est définie par défaut, mais ce n'est pas le cas dans les VM.

  7. Extrayez les identifiants Container Registry à utiliser avec la commande docker :

    docker-credential-gcr configure-docker
    
  8. Exécutez l'image de conteneur du client gRPC :

    docker run --rm -v $(pwd)/cert.pem:/data/cert.pem \
        --add-host grpc.example.com:$(cat ilb-ip.txt) \
        gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client \
        --address=grpc.example.com:443
    

    Le résultat ressemble à ceci :

    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb

    Ce résultat montre que les pods du serveur gRPC (nommés greeter-*) traitent les requêtes gRPC conformément à la configuration de loadBalancer dans la règle de destination Istio, dans le cas présent ROUND_ROBIN.

  9. Quittez la session SSH :

    exit
    

Examiner le code source

Pour mieux comprendre la configuration de l'équilibrage de charge, vous pouvez consulter le code source de l'exemple d'application.

Par exemple, pour comprendre les messages affichés par le client gRPC, consultez le code source Go du serveur et du client. Lorsque le serveur gRPC traite une requête, il recherche le nom d'hôte et l'ajoute en tant qu'en-tête de réponse nommé hostname. Étant donné que le serveur est exécuté dans un pod Kubernetes, le nom d'hôte correspond au nom du pod.

hostname, err := os.Hostname()
if err != nil {
	log.Printf("Unable to get hostname %v", err)
}
if hostname != "" {
	grpc.SendHeader(ctx, metadata.Pairs("hostname", hostname))
}

Lorsque le client gRPC reçoit une réponse du serveur, il obtient l'en-tête hostname et l'affiche sur la console.

if len(header["hostname"]) > 0 {
	hostname = header["hostname"][0]
}
log.Printf("%s from %s", r.Message, hostname)

Pour comprendre les noms des pods Kubernetes affichés sur la console par le client gRPC, consultez la configuration d'Istio pour le serveur gRPC. Notez que l'objet DestinationRule spécifie ROUND_ROBIN comme algorithme loadBalancer. Ce dernier explique la rotation des requêtes entrantes entre les pods du déploiement Kubernetes.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: greeter
spec:
  host: greeter
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    tls:
      mode: ISTIO_MUTUAL

Dépannage

Si vous rencontrez des problèmes avec ce tutoriel, nous vous recommandons de consulter les documents ci-dessous :

Nettoyer

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud, procédez comme suit :

  1. Dans Cloud Shell, supprimez le cluster GKE :

    gcloud container clusters delete grpc-istio-ilb-tutorial --quiet --async
    
  2. Supprimez les images dans Container Registry :

    gcloud container images delete gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client \
        --force-delete-tags --quiet
    gcloud container images delete gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-server \
        --force-delete-tags --quiet
    
  3. Supprimez l'instance Compute Engine :

    gcloud compute instances delete grpc-istio-ilb-tutorial-client-vm --quiet
    

Étapes suivantes