Multi-Cluster-Mesh-Netzwerk in GKE einrichten

In dieser Anleitung wird erläutert, wie Sie zwei Cluster mit Mesh CA oder Istio CA zu einem einzigen Anthos Service Mesh zusammenführen und das clusterübergreifende Load-Balancing aktivieren. Sie können diesen Prozess problemlos erweitern, um eine beliebige Anzahl von Clustern in Ihr Mesh-Netzwerk einzubinden.

Eine Anthos Service Mesh-Konfiguration mit mehreren Clustern kann in mehreren wichtigen Unternehmensszenarien wie Skalierung, Standortwahl und Isolation eine Lösung sein. Weitere Informationen finden Sie unter Multi-Cluster-Anwendungsfälle.

Vorbereitung

In dieser Anleitung wird davon ausgegangen, dass Sie mindestens zwei Google Cloud-GKE-Cluster haben, die folgende Anforderungen erfüllen:

Projekt- und Clustervariablen festlegen

  1. Legen Sie einen Arbeitsordner für die Beispiele fest, mit denen Sie prüfen, ob das clusterübergreifende Load-Balancing funktioniert. Die Beispiele befinden sich in einem Unterverzeichnis im Verzeichnis --output_dir, das Sie im Befehl asmcli install angegeben haben. Ändern Sie im folgenden Befehl OUTPUT_DIR in das Verzeichnis, das Sie in --output_dir angegeben haben, und ändern Sie ASM_VERSION in die Anthos Service Mesh-Version, z. B. 1.11.8-asm.4.

    export SAMPLES_DIR=OUTPUT_DIR/istio-ASM_VERSION
    
  2. Erstellen Sie die folgenden Umgebungsvariablen für die Projekt-ID, die Clusterzone oder -region, den Clusternamen und den Kontext.

    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}"
    
  3. Wenn es sich um neu erstellte Cluster handelt, müssen Sie mit den folgenden gcloud-Befehlen Anmeldedaten für jeden Cluster abrufen. Andernfalls ist der zugehörige context nicht für die nächsten Schritte dieser Anleitung verfügbar:

    Die Befehle hängen vom Clustertyp ab, entweder regional oder zonal:

    Regional

    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}
    

Firewallregel erstellen

In einigen Fällen müssen Sie eine Firewallregel erstellen, um clusterübergreifenden Traffic zuzulassen. In folgenden Fällen müssen Sie beispielsweise eine Firewallregel erstellen:

  • Sie verwenden unterschiedliche Subnetze für die Cluster in Ihrem Mesh-Netzwerk.
  • Ihre Pods öffnen andere Ports als 443 und 15002.

GKE fügt jedem Knoten automatisch Firewallregeln hinzu, die Traffic innerhalb eines Subnetzes zulassen. Wenn Ihr Mesh-Netzwerk mehrere Subnetze enthält, müssen Sie die Firewallregeln explizit so einrichten, dass subnetzübergreifender Traffic zulässig ist. Sie müssen dabei für jedes Subnetz eine neue Firewallregel hinzufügen, die die CIDR-Blöcke der Quell-IP-Adresse und die Zielports des gesamten eingehenden Traffics zulässt.

Die folgende Anleitung ermöglicht die Kommunikation zwischen allen Clustern in Ihrem Projekt oder nur zwischen $CLUSTER_1 und $CLUSTER_2.

  1. Sammeln Sie Informationen zum Netzwerk Ihres Clusters.

    Alle Projektcluster

    Wenn sich die Cluster im selben Projekt befinden, können Sie den folgenden Befehl verwenden, um die Kommunikation zwischen allen Clustern in Ihrem Projekt zuzulassen. Wenn in Ihrem Projekt Cluster enthalten sind, die Sie nicht verfügbar machen möchten, verwenden Sie den Befehl auf dem Tab Bestimmte Cluster.

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

    Bestimmte Cluster

    Der folgende Befehl ermöglicht die Kommunikation zwischen $CLUSTER_1 und $CLUSTER_2 und macht keine anderen Cluster in Ihrem Projekt verfügbar.

    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. Firewallregel erstellen

    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
    

Endpunkterkennung zwischen Clustern konfigurieren

Zum Konfigurieren der Endpunkterkennung zwischen GKE-Clustern führen Sie asmcli create-mesh aus. Dieser Befehl:

  • Registriert alle Cluster in derselben Flotte
  • Konfiguriert das Mesh-Netzwerk so, dass der Workload Identity der Flotte vertraut wird
  • Erstellt Remote-Secrets

Sie können entweder den URI für jeden Cluster oder den Pfad zur kubeconfig-Datei angeben.

Cluster-URI

Ersetzen Sie im folgenden Befehl FLEET_PROJECT_ID durch die Projekt-ID des Flottenhostprojekts und den Cluster-URI durch den Clusternamen, die Zone oder Region und die Projekt-ID für jeden Cluster. In diesem Beispiel werden nur zwei Cluster gezeigt. Sie können aber den Befehl ausführen, um die Endpunkterkennung für zusätzliche Cluster zu aktivieren, wobei das GKE Hub-Dienstlimit gilt.

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

kubeconfig-Datei

Ersetzen Sie im folgenden Befehl FLEET_PROJECT_ID durch die Projekt-ID des Flottenhostprojekts und PATH_TO_KUBECONFIG durch den Pfad zu jeder kubeconfig-Datei. In diesem Beispiel werden nur zwei Cluster gezeigt. Sie können jedoch den Befehl ausführen, um die Endpunkterkennung auf zusätzlichen Clustern zu aktivieren. Dabei gilt die maximal zulässige Anzahl von Clustern, die Sie Ihrer Flotte hinzufügen können..

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

Autorisierte Netzwerke für private Cluster konfigurieren

Führen Sie die Schritte dieses Abschnitts nur aus, wenn die folgenden Bedingungen für Ihr Mesh-Netzwerk zutreffen:

Wenn Sie mehrere private Cluster bereitstellen, muss die Anthos Service Mesh-Steuerungsebene in jedem Cluster die GKE-Steuerungsebene der Remote-Cluster aufrufen. Um Traffic zuzulassen, müssen Sie den autorisierten Netzwerken der Remote-Cluster den Pod-Adressbereich im aufrufenden Cluster hinzufügen.

  1. Rufen Sie den CIDR-Block des Pod-IP-Adressbereichs für jeden Cluster ab:

    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. Fügen Sie den Remote-Clustern die CIDR-Blöcke des Pod-IP-Adressbereichs im Kubernetes-Clusters hinzu:

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

    Weitere Informationen finden Sie unter Cluster mit autorisierten Netzwerken erstellen.

  3. Prüfen Sie, ob die autorisierten Netzwerke aktualisiert wurden:

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

Globalen Zugriff auf Steuerungsebene aktivieren

Führen Sie die Schritte dieses Abschnitts nur aus, wenn die folgenden Bedingungen für Ihr Mesh-Netzwerk zutreffen:

  • Sie verwenden private Cluster.
  • Sie verwenden unterschiedliche Subnetze für die Cluster in Ihrem Mesh-Netzwerk.

Sie müssen den globalen Zugriff auf Steuerungsebene aktivieren, damit die Anthos Service Mesh-Steuerungsebene in jedem Cluster die GKE-Steuerungsebene der Remote-Cluster aufrufen kann.

  1. Globalen Zugriff auf Steuerungsebene aktivieren

    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. Prüfen Sie, ob der globale Zugriff auf die Steuerungsebene aktiviert ist:

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

    Im Abschnitt privateClusterConfig wird in der Ausgabe der Status masterGlobalAccessConfig angezeigt.

Endpunkterkennung zwischen privaten Clustern konfigurieren

Wenn Sie private Cluster nutzen, müssen Sie die privaten IP-Adressen der Remote-Cluster anstelle der öffentlichen IP-Adressen konfigurieren, da nicht auf die öffentlichen IP-Adressen zugegriffen werden kann.

  1. Rufen Sie die privaten IP-Adressen für die privaten Cluster ab und ersetzen Sie die öffentlichen IP-Adressen durch die Secrets in den temporären Dateien:

    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
    
  2. Wenden Sie die neuen Secrets auf die Cluster an:

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

Deployment prüfen

In diesem Abschnitt wird erläutert, wie Sie die Beispieldienste HelloWorld und Sleep in Ihrer Multi-Cluster-Umgebung bereitstellen, um zu überprüfen, ob das clusterübergreifende Load-Balancing funktioniert.

Sidecar-Injektion aktivieren

  1. Verwenden Sie den folgenden Befehl, um den Wert des Überarbeitungslabels des Diensts istiod zu ermitteln, das Sie in späteren Schritten verwenden.

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

    Die Ausgabe sieht dann ungefähr so aus:

    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

    Notieren Sie sich den Wert des Überarbeitungslabels istiod aus der Ausgabe in der Spalte LABELS, das auf das Präfix istio.io/rev= folgt. In diesem Beispiel ist der Wert asm-173-3. Verwenden Sie den Überarbeitungswert in den Schritten im nächsten Abschnitt.

HelloWorld-Dienst installieren

  1. Erstellen Sie den Beispiel-Namespace und die Dienstdefinition in jedem Cluster. Ersetzen Sie im folgenden Befehl REVISION durch das Überarbeitungslabel istiod, das Sie im vorherigen Schritt notiert haben.

    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
    

    Dabei ist REVISION das Versionslabel istiod, das Sie zuvor notiert haben.

    Die Ausgabe sieht so aus:

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

    Sie können label "istio-injection" not found. ignorieren.

  2. Erstellen Sie in beiden Clustern den HelloWorld-Dienst:

    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
    

HelloWorld v1 und v2 in jedem Cluster bereitstellen

  1. Stellen Sie HelloWorld v1 in CLUSTER_1 und v2 in CLUSTER_2 bereit. Das erleichtert später die Prüfung des clusterübergreifenden Load-Balancings.

    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. Prüfen Sie mit den folgenden Befehlen, ob HelloWorld v1 und v2 ausgeführt werden. Prüfen Sie, ob die Ausgabe in etwa so aussieht:

    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

Sleep-Dienst bereitstellen

  1. Stellen Sie den Sleep-Dienst in beiden Clustern bereit. Dieser Pod generiert künstlichen Netzwerktraffic zur Veranschaulichung:

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl apply --context=${CTX} \
            -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample
    done
    
  2. Warten Sie, bis der Sleep-Dienst in jedem Cluster gestartet wurde. Prüfen Sie, ob die Ausgabe in etwa so aussieht:

    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

Clusterübergreifendes Load-Balancing prüfen

Rufen Sie den HelloWorld-Dienst mehrmals auf und prüfen Sie die Ausgabe, um abwechselnde Antworten von v1 und v2 zu prüfen:

  1. Rufen Sie den Dienst HelloWorld auf:

    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}')" \
        -- curl -sS helloworld.sample:5000/hello
    

    Die Ausgabe sollte in etwa so aussehen:

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Rufen Sie den Dienst HelloWorld noch einmal auf:

    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}')" \
        -- curl -sS helloworld.sample:5000/hello
    

    Die Ausgabe sollte in etwa so aussehen:

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

Sie haben Ihr Anthos Service Mesh mit Load-Balancing und mehreren Clustern geprüft.

HelloWorld-Dienst bereinigen

Entfernen Sie nach der Prüfung des Load-Balancings die Dienste HelloWorld und Sleep aus dem Cluster.

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