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.

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. Crie o namespace de exemplo em cada cluster.

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl create --context=${CTX} namespace sample
    done
    
  2. Ative a injeção de sidecar nos espaços de nomes criados.

    Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:

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

    Recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada: siga estas instruções:

    1. Use o seguinte comando para localizar a etiqueta de revisão em istiod:

      kubectl get deploy -n istio-system -l app=istiod -o \
          jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
      
    2. Aplique a etiqueta de revisão ao espaço de nomes. No comando seguinte, REVISION_LABEL é o valor da etiqueta de revisão istiod que anotou no passo anterior.

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

Instale o serviço HelloWorld

  • 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}