Configure uma malha de vários clusters no GKE

Este guia explica como juntar dois clusters num único Cloud Service Mesh usando a AC de malha ou a AC do Istio, e ativar o equilíbrio de carga entre clusters. Pode expandir facilmente este processo para incorporar qualquer número de clusters na sua malha.

Uma configuração de Cloud Service Mesh com vários clusters pode resolver vários cenários empresariais cruciais, como a escala, a localização e o isolamento. Para mais informações, consulte o artigo Exemplos de utilização com vários clusters.

Pré-requisitos

Este guia pressupõe que tem dois ou mais Google Cloud clusters do GKE que cumprem os seguintes requisitos:

Definir variáveis de projeto e cluster

  1. Crie as seguintes variáveis de ambiente para o ID do projeto, a zona ou a região do cluster, o nome do cluster e o contexto.

    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 estes forem clusters criados recentemente, certifique-se de que obtém credenciais para cada cluster com os seguintes comandos gcloud. Caso contrário, os context associados não vão estar disponíveis para utilização nos passos seguintes deste guia.

    Os comandos dependem do tipo de cluster, regional ou 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}
    

Crie uma regra de firewall

Em alguns casos, tem de criar uma regra de firewall para permitir o tráfego entre clusters. Por exemplo, tem de criar uma regra de firewall se:

  • Usar sub-redes diferentes para os clusters na sua malha.
  • Os seus pods abrem portas que não sejam 443 e 15002.

O GKE adiciona automaticamente regras de firewall a cada nó para permitir o tráfego na mesma sub-rede. Se a sua malha contiver várias sub-redes, tem de configurar explicitamente as regras de firewall para permitir o tráfego entre sub-redes. Tem de adicionar uma nova regra de firewall para cada sub-rede para permitir os blocos CIDR de IP de origem e as portas de destino de todo o tráfego recebido.

As instruções seguintes permitem a comunicação entre todos os clusters no seu projeto ou apenas entre $CLUSTER_1 e $CLUSTER_2.

  1. Recolha informações sobre a rede dos seus clusters.

    Todos os clusters de projetos

    Se os clusters estiverem no mesmo projeto, pode usar o seguinte comando para permitir a comunicação entre todos os clusters no seu projeto. Se existirem clusters no seu projeto que não quer expor, use o comando no separador Clusters específicos.

    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 específicos

    O comando seguinte permite a comunicação entre $CLUSTER_1 e $CLUSTER_2 e não expõe outros clusters no seu projeto.

    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. Crie a regra de 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
    

    Piloto automático

    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
    

Configure a descoberta de pontos finais

Os passos necessários para configurar a deteção de pontos finais dependem de preferir usar a API declarativa em clusters numa frota ou ativá-la manualmente em clusters públicos ou clusters privados.

Ative a deteção de pontos finais entre clusters públicos ou privados com a API declarativa (pré-visualização)

Pode ativar a deteção de pontos finais em clusters públicos ou privados numa frota aplicando a configuração "multicluster_mode":"connected" no mapa de configuração asm-options. Os clusters com esta configuração ativada na mesma frota têm a deteção de serviços entre clusters ativada automaticamente entre si.

Este método está disponível para instalações geridas do Cloud Service Mesh em todos os canais de lançamento. Esta é também a forma preferencial de configurar a deteção de pontos finais de vários clusters se tiver aprovisionado a malha de serviços na nuvem gerida através da funcionalidade Ativar malha de serviços na nuvem quando criar um novo cluster do GKE na Google Cloud consola.

Antes de continuar, tem de criar uma regra de firewall.

Para vários projetos, tem de adicionar manualmente FLEET_PROJECT_ID.svc.id.goog a trustDomainAliases na meshConfig da revisão, se ainda não estiver presente.

Ativar

Se o asm-options configmap já existir no seu cluster, ative a deteção de pontos finais para o cluster:

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

Se o asm-options configmap ainda não existir no seu cluster, crie-o com os dados associados e ative a deteção de pontos finais para o cluster:

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

Desativar

Desative a descoberta de pontos finais para um cluster:

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

Se anular o registo de um cluster na frota sem desativar a deteção de pontos finais, os segredos podem permanecer no cluster. Tem de limpar manualmente todos os segredos restantes.

  1. Execute o seguinte comando para encontrar segredos que requerem limpeza:

    kubectl get secrets -n istio-system -l istio.io/owned-by=mesh.googleapis.com,istio/multiCluster=true
    
  2. Elimine cada segredo:

    kubectl delete secret SECRET_NAME
    

    Repita este passo para cada segredo restante.

Configure a deteção de pontos finais entre clusters públicos

Para configurar a deteção de pontos finais entre clusters do GKE, execute o comando asmcli create-mesh. Este comando:

  • Regista todos os clusters na mesma frota.
  • Configura a malha para confiar na identidade da carga de trabalho da frota.
  • Cria segredos remotos.

Pode especificar o URI para cada cluster ou o caminho do ficheiro kubeconfig.

URI do cluster

No comando seguinte, substitua FLEET_PROJECT_ID pelo ID do projeto anfitrião da frota e o URI do cluster pelo nome do cluster, a zona ou a região e o ID do projeto para cada cluster. Este exemplo mostra apenas dois clusters, mas pode executar o comando para ativar a deteção de pontos finais em clusters adicionais, sujeito ao número máximo permitido de clusters que pode adicionar à sua frota.

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

ficheiro kubeconfig

No comando seguinte, substitua FLEET_PROJECT_ID pelo ID do projeto do projeto anfitrião da frota e PATH_TO_KUBECONFIG pelo caminho para cada ficheiro kubeconfig. Este exemplo mostra apenas dois clusters, mas pode executar o comando para ativar a deteção de pontos finais em clusters adicionais, sujeito ao número máximo permitido de clusters que pode adicionar à sua frota.

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

Configure a descoberta de pontos finais entre clusters privados

  1. Configure segredos remotos para permitir o acesso do servidor da API ao cluster para o plano de controlo da Cloud Service Mesh do outro cluster. Os comandos dependem do tipo de Cloud Service Mesh (no cluster ou gerido):

    A. Para a malha de serviços na nuvem no cluster, tem de configurar os IPs privados em vez dos IPs públicos, porque os IPs públicos não são acessíveis:

    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. Para o Managed Cloud Service Mesh:

    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. Aplique os novos segredos nos clusters:

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

Configure redes autorizadas para clusters privados

Siga esta secção apenas se todas as condições seguintes se aplicarem à sua malha:

Quando implementa vários clusters privados, o plano de controlo da malha de serviços na nuvem em cada cluster tem de chamar o plano de controlo do GKE dos clusters remotos. Para permitir o tráfego, tem de adicionar o intervalo de endereços do pod no cluster de chamada às redes autorizadas dos clusters remotos.

  1. Obtenha o bloco CIDR de IP do agrupamento para cada 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. Adicione os blocos CIDR de IP de pods do cluster do Kubernetes aos clusters remotos:

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

    Para mais informações, consulte o artigo Criar um cluster com redes autorizadas.

  3. Confirme se as redes autorizadas estão atualizadas:

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

Ative o acesso global ao plano de controlo

Siga esta secção apenas se todas as condições seguintes se aplicarem à sua malha:

  • Está a usar clusters privados.
  • Usar regiões diferentes para os clusters na sua rede de malha.

Tem de ativar o acesso global do plano de controlo para permitir que o plano de controlo da Cloud Service Mesh em cada cluster chame o plano de controlo do GKE dos clusters remotos.

  1. Ative o acesso global do plano de controlo:

    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. Verifique se o acesso global do plano de controlo está ativado:

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

    A secção privateClusterConfig na saída apresenta o estado de masterGlobalAccessConfig.

Valide a conetividade multicluster

Esta secção explica como implementar os serviços de exemplo HelloWorld e Sleep no seu ambiente de vários clusters para verificar se o equilíbrio de carga entre clusters funciona.

OUTPUT_DIR/istio-${ASM_VERSION%+*}/samples

Defina a variável para o diretório de exemplos

  1. Navegue para onde asmcli foi transferido e execute o seguinte comando para definir ASM_VERSION

    export ASM_VERSION="$(./asmcli --version)"
    
  2. Defina uma pasta de trabalho para os exemplos que usa para verificar se o equilíbrio de carga entre clusters funciona. Os exemplos estão localizados num subdiretório no diretório --output_dir que especificou no comando asmcli install. No comando seguinte, altere OUTPUT_DIR para o diretório que especificou em --output_dir.

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

Ative a injeção de sidecar

  1. Localize o valor da etiqueta de revisão, que usa em passos posteriores. O passo depende do tipo de Cloud Service Mesh (gerido ou no cluster).

    Gerido

    Use o comando seguinte para localizar a etiqueta de revisão, que vai usar nos passos posteriores.

    kubectl get controlplanerevision -n istio-system

    O resultado tem um aspeto semelhante ao seguinte:

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

    No resultado, na coluna NAME, tome nota do valor da etiqueta de revisão. Neste exemplo, o valor é asm-managed-rapid. Use o valor da revisão nos passos da secção seguinte.

    No cluster

    Use o comando seguinte para localizar a etiqueta de revisão, que vai usar nos passos posteriores.

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

    O resultado tem um aspeto semelhante ao seguinte:

     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
     

    Na saída, na coluna LABELS, repare no valor da etiqueta de revisão istiod, que segue o prefixo istio.io/rev=. Neste exemplo, o valor é asm-173-3. Use o valor da revisão nos passos da secção seguinte.

Instale o serviço HelloWorld

  1. Crie o namespace de exemplo e a definição de serviço em cada cluster. No comando seguinte, substitua REVISION pela istiod etiqueta de revisão que anotou no passo anterior.

    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
    

    onde REVISION é a etiqueta de revisão istiod que anotou anteriormente.

    O resultado é:

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

    Pode ignorar com segurança label "istio-injection" not found.

  2. Crie o serviço HelloWorld em ambos os 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
    

Implemente o HelloWorld v1 e v2 em cada cluster

  1. Implemente HelloWorld v1 em CLUSTER_1 e v2 em CLUSTER_2, o que ajuda mais tarde a validar o balanceamento de carga entre clusters:

    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. Confirme se o HelloWorld v1 e o v2 estão a ser executados através dos seguintes comandos. Verifique se o resultado é semelhante ao apresentado:

    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

Implemente o serviço de sono

  1. Implemente o serviço Sleep em ambos os clusters. Este pod gera tráfego de rede artificial para fins de demonstração:

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl apply --context=${CTX} \
            -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample
    done
    
  2. Aguarde que o serviço Sleep seja iniciado em cada cluster. Verifique se o resultado é semelhante ao apresentado:

    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

Valide o balanceamento de carga entre clusters

Chame o serviço HelloWorld várias vezes e verifique o resultado para validar respostas alternadas da v1 e v2:

  1. Ligue para o serviço 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'
    

    O resultado é semelhante ao apresentado:

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Ligue novamente para o serviço 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'
    

    O resultado é semelhante ao apresentado:

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

Parabéns, validou a sua malha de serviços na nuvem com vários clusters e equilíbrio de carga!

Limpe o serviço HelloWorld

Quando terminar a validação do equilíbrio de carga, remova o serviço HelloWorld e Sleep do cluster.

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