Configura una malla de varios clústeres en GKE

En esta guía, se explica cómo unir dos clústeres en una sola Cloud Service Mesh mediante la CA de Mesh o la CA de Istio, y habilitar el balanceo de cargas entre clústeres. Puedes ampliar con facilidad este proceso para incorporar cualquier cantidad de clústeres en la malla.

Una configuración de Cloud Service Mesh de varios clústeres puede resolver varias situaciones empresariales fundamentales, como el escalamiento, la ubicación y el aislamiento. Para obtener más información, consulta Casos de uso de varios clústeres.

Requisitos previos

En esta guía, se da por hecho que tienes dos o más clústeres de GKE de Google Cloud que cumplen los siguientes requisitos:

Configura variables de proyecto y clúster

  1. Crea las siguientes variables de entorno para el ID del proyecto, la zona o región del clúster, el nombre y el contexto del clúster.

    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. Si estos clústeres son nuevos, asegúrate de recuperar las credenciales para cada uno con los siguientes comandos de gcloud. De lo contrario, su context asociado no estará disponible para su uso en los pasos siguientes de esta guía.

    Los comandos dependen del tipo de clúster, ya sea regional o 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}
    

Crear regla de firewall

En algunos casos, debes crear una regla de firewall para permitir el tráfico entre clústeres. Por ejemplo, debes crear una regla de firewall si se cumple lo siguiente:

  • Usas subredes diferentes para los clústeres de tu malla.
  • Tus Pods abren puertos distintos de 443 y 15002.

GKE agrega automáticamente reglas de firewall a cada nodo para permitir el tráfico dentro de la misma subred. Si tu malla contiene varias subredes, debes configurar explícitamente las reglas de firewall para permitir el tráfico entre subredes. Debes agregar una regla de firewall nueva para cada subred a fin de permitir los bloques CIDR de IP de destino y los puertos de destino de todo el tráfico entrante.

Las siguientes instrucciones permiten la comunicación entre todos los clústeres de tu proyecto o solo entre $CLUSTER_1 y $CLUSTER_2.

  1. Recopila información sobre la red de tus clústeres.

    Todos los clústeres del proyecto

    Si los clústeres están en el mismo proyecto, puedes usar el siguiente comando para permitir la comunicación entre todos los clústeres del proyecto. Si hay clústeres en tu proyecto que no deseas exponer, usa el comando en la pestaña Clústeres 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}"))
    

    Clústeres específicos

    El siguiente comando permite la comunicación entre $CLUSTER_1 y $CLUSTER_2, y no expone otros clústeres en tu proyecto.

    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 regla 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
    

    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 la detección de extremos

Los pasos necesarios para configurar la detección de extremos dependen de si prefieres usar laAPI declarativa en clústeres de una flota o habilitarla de forma manual en clústeres públicos o clústeres privados.

Configura el descubrimiento de extremos entre clústeres públicos

Para configurar la detección de extremos entre clústeres de GKE, ejecuta asmcli create-mesh. Este comando realiza las siguientes acciones:

  • Registra todos los clústeres en la misma flota.
  • Configura la malla para que confíe en la identidad de carga de trabajo de la flota.
  • Crea secretos remotos.

Puedes especificar el URI para cada clúster o la ruta del archivo kubeconfig.

URI del clúster

En el siguiente comando, reemplaza FLEET_PROJECT_ID por el ID del proyecto host de la flota y el URI del clúster por el nombre, la zona o región y el ID del proyecto para cada clúster. En este ejemplo, solo se muestran dos clústeres, pero puedes ejecutar el comando para habilitar el descubrimiento de extremos en clústeres adicionales, sujeto a la cantidad máxima permitida de clústeres que puedes agregar a tu flota.

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

Archivo kubeconfig

En el siguiente comando, reemplaza: FLEET_PROJECT_ID por el ID del proyecto del proyecto host de la flota y PATH_TO_KUBECONFIG por la ruta de acceso a archivo kubeconfig. En este ejemplo, solo se muestran dos clústeres, pero puedes ejecutar el comando para habilitar el descubrimiento de extremos en clústeres adicionales, sujeto a la cantidad máxima permitida de clústeres que puedes agregar a tu flota.

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

Configura el descubrimiento de extremos entre clústeres privados

  1. Configura secretos remotos para permitir que el servidor de API acceda al clúster al plano de control de Cloud Service Mesh del otro clúster. Los comandos dependen del tipo de Cloud Service Mesh (ya sea en el clúster o administrado):

    A. Para Cloud Service Mesh en el clúster, debes configurar las IP privadas en lugar de las IP públicas, ya que no se puede acceder a las IP públicas:

    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 Cloud Service Mesh administrada, haz lo siguiente:

    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. Aplica los Secrets nuevos en los clústeres:

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

Configura redes autorizadas para clústeres privados

Sigue esta sección solo si se cumplen todas las siguientes condiciones en la malla:

Cuando se implementan varios clústeres privados, el plano de control de Cloud Service Mesh en cada clúster debe llamar al plano de control de GKE de los clústeres remotos. Para permitir el tráfico, debes agregar el rango de direcciones del Pod en el clúster que realiza la llamada a las redes autorizadas de los clústeres remotos.

  1. Obtén el bloque CIDR de IP del Pod para cada clúster:

    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. Agrega los bloques CIDR de IP del Pod de clúster de Kubernetes a los clústeres 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 obtener más información, consulta Crea un clúster con redes autorizadas.

  3. Verifica que las redes autorizadas estén actualizadas:

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

Habilita el acceso global al plano de control

Sigue esta sección solo si se cumplen todas las siguientes condiciones en la malla:

  • Usas clústeres privados.
  • Usas subredes diferentes para los clústeres de tu malla.

Debes habilitar el acceso global al plano de control para permitir que el plano de control de Cloud Service Mesh en cada clúster llame al plano de control de GKE de los clústeres remotos.

  1. Habilita el acceso global al plano de control

    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. Verifica que el acceso global al plano de control esté habilitado:

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

    La sección privateClusterConfig en el resultado muestra el estado de masterGlobalAccessConfig.

Verifica la conectividad de varios clústeres

En esta sección, se explica cómo implementar los servicios HelloWorld y Sleep de muestra en el entorno de varios clústeres para verificar que el balanceo de cargas entre clústeres funcione.

Configura una variable para el directorio de muestras

  1. Navega al lugar en que se descargó asmcli y ejecuta el siguiente comando para configurar ASM_VERSION

    export ASM_VERSION="$(./asmcli --version)"
    
  2. Configura una carpeta de trabajo para las muestras que usas para verificar que funcione el balanceo de cargas entre clústeres. Las muestras se encuentran en un subdirectorio en el directorio --output_dir que especificaste en el comando asmcli install. En el siguiente comando, cambia OUTPUT_DIR por el directorio que especificaste en --output_dir.

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

Habilita la inyección de sidecar

  1. Crea el espacio de nombres de muestra en cada clúster.

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl create --context=${CTX} namespace sample
    done
    
  2. Habilita la inserción de sidecar en los espacios de nombres creados.

    Recomendado: Ejecuta el siguiente comando para aplicar la etiqueta de inserción predeterminada al espacio de nombres:

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

    Te recomendamos que uses la inserción predeterminada, pero también se admite la inserción basada en revisiones: Usa las siguientes instrucciones:

    1. Usa el siguiente comando para encontrar la etiqueta de revisión en istiod:

      kubectl get deploy -n istio-system -l app=istiod -o \
          jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
      
    2. Aplica la etiqueta de revisión a los espacios de nombres. En el siguiente comando, REVISION_LABEL es el valor de la etiqueta de revisión istiod que anotaste en el paso anterior.

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

Instala el servicio HelloWorld

  • Crea el servicio HelloWorld en ambos clústeres:

    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
    

Implementa HelloWorld v1 y v2 en cada clúster

  1. Implementa HelloWorld v1 en CLUSTER_1 y v2 en CLUSTER_2, lo que más adelante ayudará a verificar el balanceo de cargas entre clústeres:

    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. Ejecuta los siguientes comandos para verificar que HelloWorld v1 y v2 se estén ejecutando. Verifica que el resultado sea similar al siguiente:

    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

Implementa el servicio de suspensión

  1. Implementa el servicio Sleep en ambos clústeres. En este Pod, se genera tráfico de red artificial con fines de demostración:

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl apply --context=${CTX} \
            -f ${SAMPLES_DIR}/samples/sleep/sleep.yaml -n sample
    done
    
  2. Espera a que se inicie el servicio Sleep en cada clúster. Verifica que el resultado sea similar al siguiente:

    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 el balanceo de cargas entre clústeres

Llama al servicio HelloWorld varias veces y observa el resultado para verificar respuestas alternativas de v1 y v2:

  1. Llama al servicio 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'
    

    El resultado es similar al que se muestra:

    Hello version: v2, instance: helloworld-v2-758dd55874-6x4t8
    Hello version: v1, instance: helloworld-v1-86f77cd7bd-cpxhv
    ...
  2. Vuelve a llamar al servicio 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'
    

    El resultado es similar al que se muestra:

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

Felicitaciones, ya verificaste el funcionamiento de Cloud Service Mesh de varios clústeres con balanceo de cargas.

Limpia el servicio HelloWorld

Cuando termines de verificar el balanceo de cargas, quita los servicios HelloWorld y Sleep del clúster.

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