Configurazione di un mesh multi-cluster su GKE

Questa guida spiega come unire due cluster in un unico Cloud Service Mesh utilizzando Mesh CA o Istio CA, e come abilitare il bilanciamento del carico tra cluster. Puoi estendere facilmente questo processo per incorporare qualsiasi numero di cluster nel tuo mesh.

Una configurazione di Cloud Service Mesh multi-cluster può risolvere diversi scenari aziendali cruciali, come scalabilità, località e isolamento. Per saperne di più, consulta Casi d'uso multi-cluster.

Prerequisiti

Questa guida presuppone che tu abbia due o più Google Cloud cluster GKE che soddisfano i seguenti requisiti:

Impostazione delle variabili di progetto e cluster

  1. Crea le seguenti variabili di ambiente per l'ID progetto, la zona o la regione del cluster, il nome del cluster e il contesto.

    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. Se si tratta di cluster appena creati, assicurati di recuperare le credenziali per ogni cluster con i seguenti comandi gcloud. In caso contrario, il context associato non sarà disponibile per l'uso nei passaggi successivi di questa guida.

    I comandi dipendono dal tipo di cluster, regionale o a livello di zona:

    Regionale

    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}
    

Crea regola firewall

In alcuni casi, devi creare una regola firewall per consentire il traffico tra cluster. Ad esempio, devi creare una regola firewall se:

  • Utilizzi subnet diverse per i cluster nel mesh.
  • I pod aprono porte diverse da 443 e 15002.

GKE aggiunge automaticamente regole firewall a ogni nodo per consentire il traffico all'interno della stessa subnet. Se il mesh contiene più subnet, devi configurare esplicitamente le regole firewall per consentire il traffico tra subnet. Devi aggiungere una nuova regola firewall per ogni subnet per consentire i blocchi CIDR IP di origine e le porte di destinazione di tutto il traffico in entrata.

Le seguenti istruzioni consentono la comunicazione tra tutti i cluster nel progetto o solo tra $CLUSTER_1 e $CLUSTER_2.

  1. Raccogli informazioni sulla rete dei cluster.

    Tutti i cluster del progetto

    Se i cluster si trovano nello stesso progetto, puoi utilizzare il seguente comando per consentire la comunicazione tra tutti i cluster del progetto. Se nel progetto sono presenti cluster che non vuoi esporre, utilizza il comando nella scheda Cluster specifici.

    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}"))
    

    Cluster specifici

    Il seguente comando consente la comunicazione tra $CLUSTER_1 e $CLUSTER_2 e non espone altri cluster nel progetto.

    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. Crea la regola firewall.

    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
    

Configura il rilevamento degli endpoint

I passaggi necessari per configurare il rilevamento degli endpoint dipendono dal fatto che tu preferisca utilizzare l'API dichiarativa tra i cluster in un parco risorse o abilitarla manualmente sui cluster pubblici o cluster privati.

Configura il rilevamento degli endpoint tra cluster pubblici

Per configurare il rilevamento degli endpoint tra i cluster GKE, esegui asmcli create-mesh. Questo comando:

  • Registra tutti i cluster nello stesso parco risorse.
  • Configura il mesh in modo che consideri attendibile l'identità del carico di lavoro del parco risorse.
  • Crea secret remoti.

Puoi specificare l'URI per ogni cluster o il percorso del file kubeconfig.

URI cluster

Nel comando seguente, sostituisci FLEET_PROJECT_ID con l'ID progetto del progetto host del parco risorse e l'URI del cluster con il nome del cluster, la zona o la regione e l'ID progetto per ogni cluster. Questo esempio mostra solo due cluster, ma puoi eseguire il comando per abilitare il rilevamento degli endpoint su cluster aggiuntivi, in base al numero massimo consentito di cluster che puoi aggiungere al parco risorse.

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

File kubeconfig

Nel comando seguente, sostituisci FLEET_PROJECT_ID con l'ID progetto del progetto host del parco risorse e PATH_TO_KUBECONFIG con il percorso di ogni kubeconfig file. Questo esempio mostra solo due cluster, ma puoi eseguire il comando per abilitare il rilevamento degli endpoint su cluster aggiuntivi, in base al numero massimo consentito di cluster che puoi aggiungere al parco risorse.

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

Configura il rilevamento degli endpoint tra cluster privati

  1. Configura i secret remoti per consentire l'accesso del server API al cluster al control plane di Cloud Service Mesh dell'altro cluster. I comandi dipendono dal tipo di Cloud Service Mesh (in-cluster o gestito):

    A. Per Cloud Service Mesh in-cluster, devi configurare gli IP privati anziché gli IP pubblici perché gli IP pubblici non sono accessibili:

    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. Per Cloud Service Mesh gestito:

    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. Applica i nuovi secret ai cluster:

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

Configura le reti autorizzate per i cluster privati

Segui questa sezione solo se tutte le seguenti condizioni si applicano al tuo mesh:

  • Utilizzi cluster privati.
  • I cluster non appartengono alla stessa subnet.
  • Le reti autorizzate sono abilitate per i cluster .

Quando esegui il deployment di più cluster privati, il control plane di Cloud Service Mesh in ogni cluster deve chiamare il control plane GKE dei cluster remoti. Per consentire il traffico, devi aggiungere l'intervallo di indirizzi dei pod nel cluster chiamante alle reti autorizzate dei cluster remoti.

  1. Recupera il blocco CIDR IP dei pod per ogni 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. Aggiungi i blocchi CIDR IP dei pod del cluster Kubernetes ai cluster remoti:

    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//;/,}
    

    Per saperne di più, consulta Creare un cluster con reti autorizzate.

  3. Verifica che le reti autorizzate siano aggiornate:

    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)"
    

Abilita l'accesso globale al control plane

Segui questa sezione solo se tutte le seguenti condizioni si applicano al tuo mesh:

  • Utilizzi cluster privati.
  • Utilizzi regioni diverse per i cluster nel mesh.

Devi abilitare l'accesso globale al control plane per consentire al control plane di Cloud Service Mesh in ogni cluster di chiamare il control plane GKE dei cluster remoti.

  1. Abilita l'accesso globale al control plane:

    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. Verifica che l'accesso globale al control plane sia abilitato:

    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 sezione privateClusterConfig nell'output mostra lo stato di masterGlobalAccessConfig.

Verifica la connettività multi-cluster

Questa sezione spiega come eseguire il deployment dei servizi di esempio HelloWorld e Sleep nell'ambiente multi-cluster per verificare che il bilanciamento del carico tra cluster funzioni.

Imposta la variabile per la directory degli esempi

  1. Vai alla posizione in cui è stato scaricato asmcli ed esegui il seguente comando per impostare ASM_VERSION

    export ASM_VERSION="$(./asmcli --version)"
    
  2. Imposta una cartella di lavoro per gli esempi che utilizzi per verificare che il bilanciamento del carico tra cluster funzioni. Gli esempi si trovano in una sottodirectory nella directory --output_dir specificata nel comando asmcli install. Nel comando seguente, modifica OUTPUT_DIR nella directory specificata in --output_dir.

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

Abilita l'inserimento di sidecar

  1. Crea lo spazio dei nomi di esempio in ogni cluster.

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl create --context=${CTX} namespace sample
    done
    
  2. Abilita l'inserimento di sidecar negli spazi dei nomi creati.

    Consigliato: esegui questo comando per applicare l'etichetta di inserimento predefinita allo spazio dei nomi:

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

    Ti consigliamo di utilizzare l'inserimento predefinito, ma è supportato anche l'inserimento basato sulla revisione: Segui queste istruzioni:

    1. Utilizza il comando seguente per individuare l'etichetta della revisione su istiod:

      kubectl get deploy -n istio-system -l app=istiod -o \
          jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
      
    2. Applica l'etichetta di revisione allo spazio dei nomi. Nel comando seguente, REVISION_LABEL è il valore dell'etichetta di revisione istiod che hai annotato nel passaggio precedente.

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

Installa il servizio HelloWorld

  • Crea il servizio HelloWorld in entrambi i cluster:

    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
    

Esegui il deployment di HelloWorld v1 e v2 in ogni cluster

  1. Esegui il deployment di HelloWorld v1 su CLUSTER_1 e di v2 su CLUSTER_2. Questa operazione ti aiuterà in un secondo momento a verificare il bilanciamento del carico tra cluster:

    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. Verifica che HelloWorld v1 e v2 siano in esecuzione utilizzando i comandi seguenti. Verifica che l'output sia simile a quello mostrato:

    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

Esegui il deployment del servizio Sleep

  1. Esegui il deployment del servizio Sleep in entrambi i cluster. Questo pod genera traffico di rete artificiale a scopo dimostrativo:

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl apply --context=${CTX} \
            -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample
    done
    
  2. Attendi l'avvio del servizio Sleep in ogni cluster. Verifica che l'output sia simile a quello mostrato:

    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

Verifica il bilanciamento del carico tra cluster

Chiama il servizio HelloWorld più volte e controlla l'output per verificare la presenza di risposte alternate dalle versioni 1 e 2:

  1. Chiama il servizio 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'
    

    L'output è simile a quello mostrato:

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Chiama di nuovo il servizio 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'
    

    L'output è simile a quello mostrato:

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

Congratulazioni, hai verificato il tuo Cloud Service Mesh multi-cluster con bilanciamento del carico.

Libera spazio nel servizio HelloWorld

Al termine della verifica del bilanciamento del carico, rimuovi i servizi HelloWorld e Sleep dal cluster.

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