Configurazione di un mesh multi-cluster su Cloud Service Mesh gestito

Questa guida spiega come unire due cluster in un unico Cloud Service Mesh utilizzando Mesh CA o Certificate Authority Service e abilitare il bilanciamento del carico cross-cluster. Puoi estendere facilmente questa procedura per incorporare un numero qualsiasi di cluster nella tua mesh.

Una configurazione di Cloud Service Mesh multi-cluster può risolvere diversi scenari aziendali cruciali, come scalabilità, posizione e isolamento. Per ulteriori informazioni, vedi Casi d'uso multi-cluster.

Prerequisiti

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

  • Cloud Service Mesh installato sui cluster. Hai bisogno di asmcli, dello strumento istioctl e dei campioni che asmcli scarica nella directory specificata in --output_dir.
  • Prima di configurare Cloud Service Mesh, i cluster nel mesh devono avere connettività tra tutti i pod. Inoltre, se unisci cluster che non si trovano nello stesso progetto, devono essere registrati nello stesso progetto host del parco risorse e i cluster devono trovarsi in una configurazione VPC condiviso insieme sulla stessa rete. Ti consigliamo inoltre di avere un progetto per ospitare il VPC condiviso e due progetti di servizio per la creazione di cluster. Per maggiori informazioni, consulta Configurazione di cluster con VPC condiviso.
  • Se utilizzi Certificate Authority Service, tutti i cluster devono avere le rispettive catene di pool di CA subordinate che puntano allo stesso pool di CA radice. In caso contrario, tutti dovranno utilizzare lo stesso pool di CA.

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 ciascun cluster con i seguenti comandi gcloud, altrimenti il relativo context non sarà disponibile per l'uso nei passaggi successivi di questa guida.

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

    Regionale

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

    A livello di zona

    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 la tua mesh contiene più subnet, devi configurare esplicitamente le regole firewall per consentire il traffico tra le 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 del tuo progetto o solo tra $CLUSTER_1 e $CLUSTER_2.

  1. Raccogli informazioni sulla rete dei tuoi 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 tuo 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 tuo 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

Abilita il rilevamento degli endpoint tra cluster pubblici o privati con l'API dichiarativa

L'abilitazione di Cloud Service Mesh gestito con l'API Fleet abiliterà il rilevamento degli endpoint per questo cluster. Se hai eseguito il provisioning di Cloud Service Mesh gestito con un altro strumento, puoi attivare manualmente l'individuazione degli endpoint nei cluster pubblici o privati di un parco risorse applicando la configurazione "multicluster_mode":"connected" nel configmap asm-options. I cluster con questa configurazione abilitata nello stesso parco risorse avranno ilService Discoveryo di rilevamento tra cluster abilitato automaticamente tra loro.

Questo è l'unico modo per configurare l'individuazione degli endpoint multi-cluster se hai l'implementazione del control plane Managed (TD) ed è il modo consigliato per configurarla se hai l'implementazione Managed (Istiod).

Prima di procedere, devi creare una regola firewall.

Attiva

Se la configmap asm-options esiste già nel tuo cluster, attiva il rilevamento degli endpoint per il cluster:

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

Se il configmap asm-options non esiste ancora nel tuo cluster, crealo con i dati associati e attiva il rilevamento degli endpoint per il cluster:

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

Disattiva

Disabilita il rilevamento degli endpoint per un cluster:

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

Se annulli la registrazione di un cluster dal parco risorse senza disattivare l'individuazione degli endpoint, i secret potrebbero rimanere nel cluster. Devi eliminare manualmente i secret rimanenti.

  1. Esegui questo comando per trovare i secret che richiedono la pulizia:

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

    kubectl delete secret SECRET_NAME
    

    Ripeti questo passaggio per ogni secret rimanente.

Verificare la connettività multicluster

Questa sezione spiega come eseguire il deployment dei servizi HelloWorld e Sleep di esempio 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 questo 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 cross-cluster funzioni. Gli esempi si trovano in una sottodirectory della 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%+*}
    

Attiva 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. Attiva lo spazio dei nomi per l'inserimento. I passaggi dipendono dall'implementazione del control plane.

    Gestito (TD)

    1. Applica 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
    

    Gestito (Istiod)

    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
    

    Se sei un utente esistente con il piano di controllo Istiod gestito: ti consigliamo di utilizzare l'inserimento predefinito, ma è supportato anche l'inserimento basato sulla revisione. Segui queste istruzioni:

    1. Esegui questo comando per individuare i canali di rilascio disponibili:

      kubectl -n istio-system get controlplanerevision
      

      L'output è simile al seguente:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      Nell'output, il valore nella colonna NAME è l'etichetta della revisione corrispondente al canale di rilascio disponibile per la versione di Cloud Service Mesh.

    2. Applica l'etichetta di revisione allo spazio dei nomi:

      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, il che 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 seguenti comandi. 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 per il sonno

  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 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 multicluster con bilanciamento del carico.

Mantenere il traffico all'interno del cluster

In alcuni casi, il comportamento predefinito del bilanciamento del carico tra cluster non è auspicabile. Per mantenere il traffico "locale al cluster" (ovvero il traffico inviato da cluster-a raggiungerà solo le destinazioni in cluster-a), contrassegna i nomi host o i caratteri jolly come clusterLocal utilizzando MeshConfig.serviceSettings.

Ad esempio, puoi applicare il traffico locale del cluster per un singolo servizio, per tutti i servizi in un determinato spazio dei nomi o a livello globale per tutti i servizi nel mesh, come segue:

per servizio

serviceSettings:
- settings:
    clusterLocal: true
  hosts:
  - "mysvc.myns.svc.cluster.local"

per spazio dei nomi

serviceSettings:
- settings:
    clusterLocal: true
  hosts:
  - "*.myns.svc.cluster.local"

globale

serviceSettings:
- settings:
    clusterLocal: true
  hosts:
  - "*"

Puoi anche perfezionare l'accesso al servizio impostando una regola globale locale del cluster e aggiungendo eccezioni esplicite, che possono essere specifiche o con caratteri jolly. Nell'esempio seguente, tutti i servizi nel cluster verranno mantenuti locali al cluster, ad eccezione di quelli nello spazio dei nomi myns:

serviceSettings:
- settings:
    clusterLocal: true
  hosts:
  - "*"
- settings:
    clusterLocal: false
  hosts:
  - "*.myns.svc.cluster.local"

Attiva il servizio cluster locale

  1. Controlla la mappa di configurazione MeshConfig nel cluster

    kubectl get configmap -n istio-system
    

    Dovresti visualizzare una mappa di configurazione con uno dei nomi istio-asm-managed, istio-asm-managed-rapid o istio-asm-managed-stable.

    Se hai eseguito la migrazione dall'implementazione ISTIOD all'implementazione TRAFFIC_DIRECTOR, potresti visualizzare più di una mappa di configurazione. In questo caso, puoi determinare il canale eseguendo il comando seguente:

    kubectl get controlplanerevision -n istio-system
    

    Il canale della revisione del piano di controllo riconciliata è quello che vuoi scegliere.

  2. Aggiorna la mappa di configurazione

    cat <<EOF > config.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: CONFIGMAP_NAME
      namespace: istio-system
    data:
      config: |
        serviceSettings:
        - settings:
            clusterLocal: true
          hosts:
          - "*"
    EOF
    

    Sostituisci CONFIGMAP_NAME con il nome della ConfigMap che hai trovato nel passaggio 1 e aggiorna la ConfigMap.

    kubectl apply --context=${CTX_1} -f config.yaml
    
  3. Verifica che la funzionalità Cluster locale funzioni come previsto utilizzando i seguenti comandi. L'output della chiamata a HelloWorld con CTX_1 è simile al seguente:

    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'
    

    Nell'output dovresti vedere Only v1 is response:

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

    Se chiami il HelloWorld con CTX_2:

    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'
    

    Nell'output dovresti vedere risposte alternate di v1 e v2.

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

Pulisci il 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}