Configurer un maillage multicluster sur GKE

Ce guide explique comment joindre deux clusters dans un seul Cloud Service Mesh à l'aide de Mesh CA ou d'Istio CA, et comment activer l'équilibrage de charge interclusters. Vous pouvez facilement étendre ce processus pour intégrer autant de clusters que vous le souhaitez dans votre maillage.

Une configuration multicluster Cloud Service Mesh peut résoudre plusieurs scénarios d'entreprise essentiels, tels que l'échelle, l'emplacement et l'isolation. Pour en savoir plus, consultez la section Cas d'utilisation multicluster.

Prérequis

Dans ce guide, nous partons du principe que vous disposez d'au moins deux clusters GKE Google Cloud répondant aux exigences suivantes :

Définir des variables de projet et de cluster

  1. Créez les variables d'environnement suivantes pour l'ID de projet, la zone ou la région du cluster, le nom du cluster et le contexte.

    export PROJECT_1=PROJECT_ID_1
    export LOCATION_1=CLUSTER_LOCATION_1
    export CLUSTER_1=CLUSTER_NAME_1
    export CTX_1="gke_${PROJECT_1}_${LOCATION_1}_${CLUSTER_1}"
    
    export PROJECT_2=PROJECT_ID_2
    export LOCATION_2=CLUSTER_LOCATION_2
    export CLUSTER_2=CLUSTER_NAME_2
    export CTX_2="gke_${PROJECT_2}_${LOCATION_2}_${CLUSTER_2}"
    
  2. S'il s'agit de nouveaux clusters, veillez à récupérer les identifiants de chaque cluster à l'aide des commandes gcloud suivantes. Sinon, la variable context associée ne sera pas disponible pour les étapes suivantes de ce guide.

    Les commandes dépendent du type de cluster, régional ou zonal :

    Régional

    gcloud container clusters get-credentials ${CLUSTER_1} --region ${LOCATION_1}
    gcloud container clusters get-credentials ${CLUSTER_2} --region ${LOCATION_2}
    

    Zonal

    gcloud container clusters get-credentials ${CLUSTER_1} --zone ${LOCATION_1}
    gcloud container clusters get-credentials ${CLUSTER_2} --zone ${LOCATION_2}
    

Créer une règle de pare-feu

Dans certains cas, vous devez créer une règle de pare-feu pour autoriser le trafic interclusters. Par exemple, vous devez créer une règle de pare-feu dans les cas suivants :

  • Vous utilisez différents sous-réseaux pour les clusters de votre maillage.
  • Vos pods ouvrent des ports autres que 443 et 15002.

GKE ajoute automatiquement des règles de pare-feu à chaque nœud pour autoriser le trafic au sein du même sous-réseau. Si votre maillage contient plusieurs sous-réseaux, vous devez configurer explicitement les règles de pare-feu pour autoriser le trafic entre sous-réseaux. Vous devez ajouter une règle de pare-feu pour chaque sous-réseau afin d'autoriser les blocs CIDR des adresses IP sources et les ports cible pour l'ensemble du trafic entrant.

Les instructions suivantes permettent d'établir la communication entre tous les clusters de votre projet, ou uniquement entre $CLUSTER_1 et $CLUSTER_2.

  1. Recueillez des informations sur le réseau de vos clusters.

    Tous les clusters du projet

    Si les clusters se trouvent dans le même projet, vous pouvez utiliser la commande suivante pour autoriser la communication entre tous les clusters de votre projet. Si vous ne souhaitez pas exposer des clusters de votre projet, exécutez la commande décrite dans l'onglet Clusters spécifiques.

    function join_by { local IFS="$1"; shift; echo "$*"; }
    ALL_CLUSTER_CIDRS=$(gcloud container clusters list --project $PROJECT_1 --format='value(clusterIpv4Cidr)' | sort | uniq)
    ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
    ALL_CLUSTER_NETTAGS=$(gcloud compute instances list --project $PROJECT_1 --format='value(tags.items.[0])' | sort | uniq)
    ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
    

    Clusters spécifiques

    La commande suivante autorise la communication entre $CLUSTER_1 et $CLUSTER_2, et n'expose pas les autres clusters de votre projet.

    function join_by { local IFS="$1"; shift; echo "$*"; }
    ALL_CLUSTER_CIDRS=$(for P in $PROJECT_1 $PROJECT_2; do gcloud --project $P container clusters list --filter="name:($CLUSTER_1,$CLUSTER_2)" --format='value(clusterIpv4Cidr)'; done | sort | uniq)
    ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
    ALL_CLUSTER_NETTAGS=$(for P in $PROJECT_1 $PROJECT_2; do gcloud --project $P compute instances list  --filter="name:($CLUSTER_1,$CLUSTER_2)" --format='value(tags.items.[0])' ; done | sort | uniq)
    ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
    
  2. Créez la règle de pare-feu.

    GKE

    gcloud compute firewall-rules create istio-multicluster-pods \
        --allow=tcp,udp,icmp,esp,ah,sctp \
        --direction=INGRESS \
        --priority=900 \
        --source-ranges="${ALL_CLUSTER_CIDRS}" \
        --target-tags="${ALL_CLUSTER_NETTAGS}" --quiet \
        --network=YOUR_NETWORK
    

    Autopilot

    TAGS=""
    for CLUSTER in ${CLUSTER_1} ${CLUSTER_2}
    do
        TAGS+=$(gcloud compute firewall-rules list --filter="Name:$CLUSTER*" --format="value(targetTags)" | uniq) && TAGS+=","
    done
    TAGS=${TAGS::-1}
    echo "Network tags for pod ranges are $TAGS"
    
    gcloud compute firewall-rules create asm-multicluster-pods \
        --allow=tcp,udp,icmp,esp,ah,sctp \
        --network=gke-cluster-vpc \
        --direction=INGRESS \
        --priority=900 --network=VPC_NAME \
        --source-ranges="${ALL_CLUSTER_CIDRS}" \
        --target-tags=$TAGS
    

Configurer la découverte des points de terminaison

Les étapes requises pour configurer la découverte des points de terminaison varient selon que vous préférez utiliser l'API déclarative sur l'ensemble des clusters d'un parc ou l'activer manuellement sur les clusters publics ou les clusters privés.

Activer la découverte de points de terminaison entre les clusters avec l'API déclarative (aperçu)

Vous pouvez activer la découverte des points de terminaison sur les clusters d'un parc en appliquant la configuration "multicluster_mode":"connected" dans le fichier ConfigMap asm-options. La détection de services interclusters est automatiquement activée entre les clusters qui disposent de cette configuration dans le même parc.

Cette méthode est disponible pour les installations gérées de Cloud Service Mesh sur toutes les versions disponibles. Avant de continuer, vous devez avoir créé une règle de pare-feu.

Pour plusieurs projets, vous devez ajouter manuellement FLEET_PROJECT_ID.svc.id.goog à trustDomainAliases dans le fichier meshConfig de la révision, s'il n'est pas déjà présent.

Activer

Si le ConfigMap asm-options existe déjà dans votre cluster, activez la découverte de points de terminaison pour le cluster :

kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"connected"}}'

Si le ConfigMap asm-options n'existe pas encore dans votre cluster, alors le créer avec les données associées et activer la détection des points de terminaison pour cluster:

kubectl --context ${CTX_1} create configmap asm-options -n istio-system --from-file <(echo '{"data":{"multicluster_mode":"connected"}}')

Désactiver

Désactivez la découverte des points de terminaison pour un cluster :

kubectl patch configmap/asm-options -n istio-system --type merge -p '{"data":{"multicluster_mode":"manual"}}'

Si vous annulez l'enregistrement d'un cluster du parc sans désactiver la découverte des points de terminaison, les secrets peuvent rester dans le cluster. Vous devez nettoyer manuellement tous les secrets restants.

  1. Exécutez la commande suivante pour rechercher les secrets nécessitant un nettoyage :

    kubectl get secrets -n istio-system -l istio.io/owned-by=mesh.googleapis.com,istio/multiCluster=true
    
  2. Supprimez chaque secret :

    kubectl delete secret SECRET_NAME
    

    Répétez cette opération pour chaque secret restant.

Configurer la découverte des points de terminaison entre les clusters publics

Pour configurer la découverte des points de terminaison entre les clusters GKE, exécutez la commande asmcli create-mesh. Cette commande :

  • enregistre tous les clusters dans le même parc ;
  • configure le réseau maillé pour approuver l'identité de charge de travail du parc ;
  • crée des secrets distants.

Vous pouvez spécifier l'URI de chaque cluster ou le chemin d'accès au fichier kubeconfig.

URI des clusters

Dans la commande suivante, remplacez FLEET_PROJECT_ID par l'ID du projet hôte de parc, et l'URI du cluster par le nom, la zone ou la région, et l'ID de projet de chaque cluster. Cet exemple n'affiche que deux clusters, mais vous pouvez exécuter la commande pour activer la découverte de points de terminaison sur des clusters supplémentaires, sous réserve du nombre maximal autorisé de clusters que vous pouvez ajouter à votre parc.

./asmcli create-mesh \
    FLEET_PROJECT_ID \
    ${PROJECT_1}/${LOCATION_1}/${CLUSTER_1} \
    ${PROJECT_2}/${LOCATION_2}/${CLUSTER_2}

Fichier kubeconfig

Dans la commande suivante, remplacez FLEET_PROJECT_ID par l'ID du projet hôte de parc etPATH_TO_KUBECONFIG par le chemin d'accès à chaque fichier kubeconfig. Cet exemple n'affiche que deux clusters, mais vous pouvez exécuter la commande pour activer la découverte de points de terminaison sur des clusters supplémentaires, sous réserve du nombre maximal autorisé de clusters que vous pouvez ajouter à votre parc.

./asmcli create-mesh \
    FLEET_PROJECT_ID \
    PATH_TO_KUBECONFIG_1 \
    PATH_TO_KUBECONFIG_2

Configurer la recherche de points de terminaison entre les clusters privés

  1. Configurez des secrets distants pour autoriser le serveur d'API à accéder au cluster au plan de contrôle Cloud Service Mesh de l'autre cluster. Les commandes disponibles dépendent Type de maillage de services Cloud (en cluster ou géré):

    A. Pour Cloud Service Mesh dans le cluster, vous devez configurer les adresses IP privées au lieu des adresses IP publiques, car ces dernières ne sont pas accessibles :

    PRIV_IP=`gcloud container clusters describe "${CLUSTER_1}" --project "${PROJECT_1}" \
     --zone "${LOCATION_1}" --format "value(privateClusterConfig.privateEndpoint)"`
    
    ./istioctl x create-remote-secret --context=${CTX_1} --name=${CLUSTER_1} --server=https://${PRIV_IP} > ${CTX_1}.secret
    
    PRIV_IP=`gcloud container clusters describe "${CLUSTER_2}" --project "${PROJECT_2}" \
     --zone "${LOCATION_2}" --format "value(privateClusterConfig.privateEndpoint)"`
    
    ./istioctl x create-remote-secret --context=${CTX_2} --name=${CLUSTER_2} --server=https://${PRIV_IP} > ${CTX_2}.secret
    

    B. Pour Cloud Service Mesh géré :

    PUBLIC_IP=`gcloud container clusters describe "${CLUSTER_1}" --project "${PROJECT_1}" \
     --zone "${LOCATION_1}" --format "value(privateClusterConfig.publicEndpoint)"`
    
    ./istioctl x create-remote-secret --context=${CTX_1} --name=${CLUSTER_1} --server=https://${PUBLIC_IP} > ${CTX_1}.secret
    
    PUBLIC_IP=`gcloud container clusters describe "${CLUSTER_2}" --project "${PROJECT_2}" \
     --zone "${LOCATION_2}" --format "value(privateClusterConfig.publicEndpoint)"`
    
    ./istioctl x create-remote-secret --context=${CTX_2} --name=${CLUSTER_2} --server=https://${PUBLIC_IP} > ${CTX_2}.secret
    
  2. Appliquez les nouveaux secrets dans les clusters :

    kubectl apply -f ${CTX_1}.secret --context=${CTX_2}
    
    kubectl apply -f ${CTX_2}.secret --context=${CTX_1}
    

Configurer des réseaux autorisés pour les clusters privés

Ne suivez cette section que si toutes les conditions suivantes s'appliquent à votre maillage :

Lors du déploiement de plusieurs clusters privés, le plan de contrôle Cloud Service Mesh dans chaque cluster doit appeler le plan de contrôle GKE clusters distants. Pour autoriser le trafic, vous devez ajouter la plage d'adresses des pods du cluster appelant aux réseaux autorisés des clusters distants.

  1. Obtenez le bloc CIDR des adresses IP de pod pour chaque cluster :

    POD_IP_CIDR_1=`gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \
      --format "value(ipAllocationPolicy.clusterIpv4CidrBlock)"`
    
    POD_IP_CIDR_2=`gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \
      --format "value(ipAllocationPolicy.clusterIpv4CidrBlock)"`
    
  2. Ajoutez les blocs CIDR d'adresses IP des pods des cluster Kubernetes aux clusters distants :

    EXISTING_CIDR_1=`gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \
     --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"`
    gcloud container clusters update ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \
    --enable-master-authorized-networks \
    --master-authorized-networks ${POD_IP_CIDR_2},${EXISTING_CIDR_1//;/,}
    
    EXISTING_CIDR_2=`gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \
     --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"`
    gcloud container clusters update ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \
    --enable-master-authorized-networks \
    --master-authorized-networks ${POD_IP_CIDR_1},${EXISTING_CIDR_2//;/,}
    

    Pour plus d'informations, consultez la section Créer un cluster avec des réseaux autorisés.

  3. Vérifiez que les réseaux autorisés sont à jour :

    gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \
     --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"
    
    gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \
     --format "value(masterAuthorizedNetworksConfig.cidrBlocks.cidrBlock)"
    

Activer l'accès mondial au plan de contrôle

Ne suivez cette section que si toutes les conditions suivantes s'appliquent à votre maillage :

  • Vous utilisez des clusters privés.
  • Vous utilisez différentes régions pour les clusters de votre maillage.

Vous devez activer l'accès mondial au plan de contrôle. pour autoriser le plan de contrôle de Cloud Service Mesh dans chaque cluster à appeler le Plan de contrôle GKE des clusters distants.

  1. Activer l'accès mondial au plan de contrôle :

    gcloud container clusters update ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1} \
     --enable-master-global-access
    
    gcloud container clusters update ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2} \
     --enable-master-global-access
    
  2. Vérifiez que l'accès mondial au plan de contrôle est activé :

    gcloud container clusters describe ${CLUSTER_1} --project ${PROJECT_1} --zone ${LOCATION_1}
    
    gcloud container clusters describe ${CLUSTER_2} --project ${PROJECT_2} --zone ${LOCATION_2}
    

    La section privateClusterConfig de la sortie affiche l'état masterGlobalAccessConfig.

Vérifier la connectivité multicluster

Cette section explique comment déployer les exemples de services HelloWorld et Sleep dans votre environnement multicluster pour vérifier que l'équilibrage de charge interclusters fonctionne.

Définir une variable pour le répertoire d'exemples

  1. Accédez à l'emplacement où asmcli a été téléchargé, puis exécutez la commande suivante pour définir ASM_VERSION.

    export ASM_VERSION="$(./asmcli --version)"
    
  2. Définissez un dossier de travail sur les exemples que vous utilisez pour vérifier que l'équilibrage de charge interclusters fonctionne. Les exemples se trouvent dans un sous-répertoire du répertoire --output_dir que vous avez spécifié dans la commande asmcli install. Dans la commande suivante, remplacez OUTPUT_DIR par le répertoire que vous avez spécifié dans --output_dir.

    export SAMPLES_DIR=OUTPUT_DIR/istio-${ASM_VERSION%+*}
    

Activer l'injection side-car

  1. Recherchez la valeur du libellé de révision, que vous utiliserez lors des étapes suivantes. L'étape dépend de votre type de maillage de services Cloud Service (géré ou en cluster).

    Géré

    Utilisez la commande suivante pour localiser le libellé de révision, que vous utiliserez lors des prochaines étapes.

    kubectl get controlplanerevision -n istio-system

    La sortie ressemble à ceci :

     NAME                RECONCILED   STALLED   AGE
     asm-managed-rapid   True         False     89d
     

    Notez la valeur du libellé de révision, affichée dans la colonne NAME de la sortie. Dans cet exemple, la valeur est asm-managed-rapid. Utilisez la valeur de révision décrite dans les étapes de la section suivante.

    Dans le cluster

    Utilisez la commande suivante pour localiser le libellé de révision, que vous utiliserez lors des prochaines étapes.

    kubectl -n istio-system get pods -l app=istiod --show-labels

    La sortie ressemble à ceci :

     NAME                                READY   STATUS    RESTARTS   AGE   LABELS
     istiod-asm-173-3-5788d57586-bljj4   1/1     Running   0          23h   app=istiod,istio.io/rev=asm-173-3,istio=istiod,pod-template-hash=5788d57586
     istiod-asm-173-3-5788d57586-vsklm   1/1     Running   1          23h   app=istiod,istio.io/rev=asm-173-3,istio=istiod,pod-template-hash=5788d57586
     

    Dans le résultat, sous la colonne LABELS, notez la valeur du libellé de révision istiod, qui suit le préfixe istio.io/rev=. Dans cet exemple, la valeur est asm-173-3. Utilisez la valeur de révision décrite dans les étapes de la section suivante.

Installer le service HelloWorld

  1. Créez l'exemple d'espace de noms et la définition de service dans chaque cluster. Dans la commande suivante, remplacez REVISION par le libellé de révision istiod noté à l'étape précédente.

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl create --context=${CTX} namespace sample
        kubectl label --context=${CTX} namespace sample \
            istio-injection- istio.io/rev=REVISION --overwrite
    done
    

    REVISION est le libellé de révision istiod que vous avez noté précédemment.

    Le résultat est :

    label "istio-injection" not found.
    namespace/sample labeled
    

    Vous pouvez ignorer label "istio-injection" not found. en toute sécurité

  2. Créez le service HelloWorld dans les deux clusters :

    kubectl create --context=${CTX_1} \
        -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \
        -l service=helloworld -n sample
    
    kubectl create --context=${CTX_2} \
        -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \
        -l service=helloworld -n sample
    

Déployer HelloWorld v1 et v2 sur chaque cluster

  1. Déployez HelloWorld v1 sur CLUSTER_1 et v2 sur CLUSTER_2, ce qui vous permet de vérifier ultérieurement l'équilibrage de charge interclusters :

    kubectl create --context=${CTX_1} \
      -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \
      -l version=v1 -n sample
    kubectl create --context=${CTX_2} \
      -f ${SAMPLES_DIR}/samples/helloworld/helloworld.yaml \
      -l version=v2 -n sample
  2. Vérifiez que HelloWorld v1 et v2 sont en cours d'exécution à l'aide des commandes suivantes. Vérifiez que le résultat ressemble à celui-ci :

    kubectl get pod --context=${CTX_1} -n sample
    NAME                            READY     STATUS    RESTARTS   AGE
    helloworld-v1-86f77cd7bd-cpxhv  2/2       Running   0          40s
    kubectl get pod --context=${CTX_2} -n sample
    NAME                            READY     STATUS    RESTARTS   AGE
    helloworld-v2-758dd55874-6x4t8  2/2       Running   0          40s

Déployer le service Sleep

  1. Déployez le service Sleep sur les deux clusters. Ce pod génère un trafic réseau artificiel à des fins de démonstration :

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl apply --context=${CTX} \
            -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample
    done
    
  2. Attendez que le service Sleep démarre dans chaque cluster. Vérifiez que le résultat ressemble à celui-ci :

    kubectl get pod --context=${CTX_1} -n sample -l app=sleep
    NAME                             READY   STATUS    RESTARTS   AGE
    sleep-754684654f-n6bzf           2/2     Running   0          5s
    kubectl get pod --context=${CTX_2} -n sample -l app=sleep
    NAME                             READY   STATUS    RESTARTS   AGE
    sleep-754684654f-dzl9j           2/2     Running   0          5s

Vérifier l'équilibrage de charge interclusters

Appelez le service HelloWorld plusieurs fois et vérifiez le résultat pour vérifier l'alternance des réponses de v1 et v2 :

  1. Appelez le service HelloWorld :

    kubectl exec --context="${CTX_1}" -n sample -c sleep \
        "$(kubectl get pod --context="${CTX_1}" -n sample -l \
        app=sleep -o jsonpath='{.items[0].metadata.name}')" \
        -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
    

    Le résultat ressemble à ceci :

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Appelez à nouveau le service HelloWorld :

    kubectl exec --context="${CTX_2}" -n sample -c sleep \
        "$(kubectl get pod --context="${CTX_2}" -n sample -l \
        app=sleep -o jsonpath='{.items[0].metadata.name}')" \
        -- /bin/sh -c 'for i in $(seq 1 20); do curl -sS helloworld.sample:5000/hello; done'
    

    Le résultat ressemble à ceci :

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...

Félicitations, vous avez vérifié votre maillage de services Cloud Service Mesh multicluster à équilibrage de charge !

Nettoyer le service HelloWorld

Lorsque vous avez terminé la vérification de l'équilibrage de charge, supprimez les services HelloWorld et Sleep de votre cluster.

kubectl delete ns sample --context ${CTX_1}
kubectl delete ns sample --context ${CTX_2}