Configurar uma malha de vários clusters no GKE

Neste guia, explicamos como mesclar dois clusters em um único Cloud Service Mesh usando a CA da Mesh ou a CA do Istio, além de ativar o balanceamento de carga entre clusters. É possível ampliar facilmente esse processo para incorporar qualquer quantidade de clusters na malha.

Uma configuração do Cloud Service Mesh de vários clusters pode resolver vários cenários corporativos cruciais, como escala, local e isolamento. Para mais informações, consulte Casos de uso de vários clusters.

Pré-requisitos

Para este guia, presumimos que você tenha dois ou mais clusters do Google Cloud GKE que atendam aos seguintes requisitos:

Como definir variáveis de projeto e de cluster

  1. Crie as seguintes variáveis de ambiente para o ID do projeto, a zona ou 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 esses forem clusters recém-criados, busque credenciais para cada cluster com os seguintes comandos gcloud. Caso contrário, o context associado não estará disponível para uso nas próximas etapas deste guia.

    Os comandos dependem do tipo de cluster, por região ou por zona:

    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}
    

Criar regra de firewall

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

  • Você usa sub-redes diferentes para os clusters na malha.
  • Os pods abrem portas diferentes de 443 e 15002.

O GKE adiciona automaticamente regras de firewall a cada nó para permitir o tráfego dentro da mesma sub-rede. Se a malha contiver várias sub-redes, será necessário configurar explicitamente as regras de firewall para permitir o tráfego entre as sub-redes. Você precisa adicionar uma nova regra de firewall para cada sub-rede para permitir os bloqueios de CIDR de IP de origem e segmentar as portas de todo o tráfego de entrada.

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

  1. Reúna informações sobre a rede dos clusters.

    Todos os clusters de projeto

    Se os clusters estiverem no mesmo projeto, use o seguinte comando para permitir a comunicação entre todos os clusters no projeto. Se você não quiser expor alguns clusters no seu projeto, use o comando na guia 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 a seguir permite a comunicação entre $CLUSTER_1 e $CLUSTER_2 e não expõe outros clusters no 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
    

Configurar a descoberta de endpoints

As etapas necessárias para configurar a descoberta de endpoints dependem da sua preferência para usar a API declarativa entre clusters em uma frota ou ativá-la manualmente em clusters públicos ou clusters particulares.

Ativar a descoberta de endpoints entre clusters públicos ou particulares com a API declarativa (pré-lançamento)

É possível ativar a descoberta de endpoints em clusters públicos ou particulares em uma frota aplicando a configuração "multicluster_mode":"connected" no configmap asm-options. Os clusters com essa configuração ativada na mesma frota terão a descoberta de serviços entre clusters ativada automaticamente entre si.

Esse método está disponível para instalações gerenciadas no Cloud Service Mesh em todos os canais de lançamento. Essa também é a maneira recomendada de configurar a descoberta de endpoints em vários clusters se você provisionou o Cloud Service Mesh gerenciado usando o recurso Ativar o Cloud Service Mesh ao criar um novo cluster do GKE no console do Google Cloud.

Antes de continuar, crie uma regra de firewall.

Para vários projetos, é necessário adicionar manualmente FLEET_PROJECT_ID.svc.id.goog a trustDomainAliases no meshConfig de revisão, caso ele ainda não esteja presente.

Ativar

Se o configmap asm-options já existe no seu cluster, ative a descoberta de endpoints para o cluster:

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

Se o configmap asm-options ainda não existe no cluster, crie-o com os dados associados e ative a descoberta de endpoints para o cluster:

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

Desativar

Desativar a descoberta de endpoints para um cluster:

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

Se você cancelar o registro de um cluster na frota sem desativar a descoberta de endpoints, os secrets poderão permanecer no cluster. Você precisa limpar manualmente todos os secrets restantes.

  1. Execute o seguinte comando para encontrar secrets que precisam de limpeza:

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

    kubectl delete secret SECRET_NAME
    

    Repita essa etapa para cada secret restante.

Configurar a descoberta de endpoints entre clusters públicos

Para configurar a descoberta de endpoints entre clusters do GKE, execute asmcli create-mesh. Esse comando:

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

É possível especificar o URI de cada cluster ou o caminho do arquivo kubeconfig.

URI do cluster

No comando a seguir, substitua FLEET_PROJECT_ID pelo ID do projeto do host da frota e o URI do cluster pelo nome do cluster, zona ou região e pelo ID do projeto de cada cluster. Este exemplo mostra apenas dois clusters, mas é possível executar o comando para ativar a descoberta de endpoints em clusters adicionais, sujeito ao número máximo permitido de clusters que podem ser adicionados à sua frota.

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

Arquivo kubeconfig

No comando a seguir, substitua FLEET_PROJECT_ID pelo ID do projeto do projeto host da frota e PATH_TO_KUBECONFIG pelo caminho para cada kubeconfig. Este exemplo mostra apenas dois clusters, mas é possível executar o comando para ativar a descoberta de endpoints em clusters adicionais, sujeito ao número máximo permitido de clusters que podem ser adicionados à sua frota.

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

Configurar a descoberta de endpoints entre clusters particulares

  1. Configure segredos remotos para permitir acesso do servidor da API ao cluster em relação ao plano de controle do Cloud Service Mesh do outro cluster. Os comandos dependem do tipo de Cloud Service Mesh (no cluster ou gerenciado):

    A. Para o Cloud Service Mesh no cluster, é preciso configurar os IPs particulares em vez dos IPs públicos porque os IPs públicos não estã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 Cloud Service Mesh gerenciado:

    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 secrets aos clusters:

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

Configurar redes autorizadas para clusters particulares

Siga esta seção somente se todas as condições a seguir se aplicarem à sua malha:

Ao implantar vários clusters particulares, o plano de controle do Cloud Service Mesh em cada cluster precisa chamar o plano de controle do GKE dos clusters remotos. Para permitir o tráfego, você precisa adicionar o intervalo de endereços do pod no cluster de chamada para as redes autorizadas dos clusters remotos.

  1. Consiga o bloco de CIDR de IP de pod 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 do pod 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 Como criar um cluster com redes autorizadas.

  3. Verifique 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)"
    

Ativar o acesso global ao plano de controle

Siga esta seção somente se todas as condições a seguir se aplicarem à sua malha:

  • Você está usando clusters particulares.
  • Você usa regiões diferentes para os clusters na malha.

É necessário ativar o acesso global ao plano de controle para permitir que o plano de controle do Cloud Service Mesh em cada cluster chame o plano de controle do GKE dos clusters remotos.

  1. Ativar o acesso global ao plano de controle:

    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 ao plano de controle 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 seção privateClusterConfig na saída exibe o status de masterGlobalAccessConfig.

Verificar a conectividade de vários clusters

Nesta seção, você verá como implantar os serviços de amostra HelloWorld e Sleep no ambiente de vários clusters para verificar se o balanceamento de carga entre eles funciona.

Definir variável para diretório de amostras

  1. Navegue até o local onde asmcli foi salvo e execute o seguinte comando para configurar o ASM_VERSION

    export ASM_VERSION="$(./asmcli --version)"
    
  2. Defina uma pasta de trabalho para as amostras que você usa para verificar se o balanceamento de carga entre clusters funciona. As amostras estão localizadas em um subdiretório, no diretório --output_dir que você especificou no comando asmcli install. No comando a seguir, altere OUTPUT_DIR para o diretório especificado em --output_dir.

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

Ative a injeção de sidecar

  1. Localize o valor do rótulo de revisão, que você vai usar em etapas futuras. A etapa depende do tipo de Cloud Service Mesh (gerenciado ou no cluster).

    Gerenciado

    Use o comando a seguir para localizar o identificador de revisão, que vai ser usado em etapas futuras.

    kubectl get controlplanerevision -n istio-system

    A resposta será semelhante a:

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

    Na saída, na coluna NAME, observe o valor do rótulo de revisão. Neste exemplo, o valor é asm-managed-rapid. Use o valor da revisão nas etapas da próxima seção.

    No cluster

    Use o comando a seguir para localizar o identificador de revisão, que vai ser usado em etapas futuras.

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

    A resposta será semelhante a:

     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, observe o valor do rótulo de revisão istiod, que segue o prefixo istio.io/rev=. Neste exemplo, o valor é asm-173-3. Use o valor da revisão nas etapas da próxima seção.

Instalar o serviço HelloWorld

  1. Crie o namespace de amostra e a definição de serviço em cada cluster. No comando a seguir, substitua REVISION pelo rótulo de revisão istiod que você anotou na etapa 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
    

    em que REVISION é o rótulo de revisão istiod que você anotou anteriormente.

    A resposta é:

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

    Você pode ignorar label "istio-injection" not found. com segurança

  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
    

Implantar o HelloWorld v1 e v2 em cada cluster

  1. Implante HelloWorld v1 em CLUSTER_1 e v2 em CLUSTER_2. Isso ajudará a verificar o balanceamento de carga entre clusters posteriormente:

    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 HelloWorld v1 e v2 estão em execução usando os seguintes comandos. Verifique se a saída é semelhante a esta:

    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

Implantar o serviço Sleep

  1. Implante o serviço Sleep nos dois clusters. Esse 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 a inicialização do serviço Sleep em cada cluster. Verifique se a saída é semelhante a esta:

    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

Verificar o balanceamento de carga entre clusters

Chame o serviço HelloWorld várias vezes e confira o resultado para verificar as respostas alternadas da v1 e da v2:

  1. Chame 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'
    

    A resposta será semelhante a esta:

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Chame o serviço HelloWorld novamente:

    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'
    

    A resposta será semelhante a esta:

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

Parabéns, você verificou seu balanceamento de carga com vários clusters do Cloud Service Mesh!

Limpar o serviço HelloWorld

Quando terminar de verificar o balanceamento de carga, remova os serviços HelloWorld e Sleep do seu cluster.

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