Configurar una malla de varios clústeres en Cloud Service Mesh gestionado

En esta guía se explica cómo unir dos clústeres en una sola malla de servicios de Cloud mediante Mesh CA o Certificate Authority Service y cómo habilitar el balanceo de carga entre clústeres. Puedes ampliar fácilmente este proceso para incorporar cualquier número de clústeres a tu malla.

Una configuración de Cloud Service Mesh de varios clústeres puede resolver varios casos prácticos cruciales para las empresas, como la escalabilidad, la ubicación y el aislamiento. Para obtener más información, consulta Casos prácticos de varios clústeres.

Requisitos previos

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

  • Cloud Service Mesh instalado en los clústeres. Necesitas asmcli, la herramienta istioctl y muestras que asmcli descarga en el directorio que has especificado en --output_dir.
  • Los clústeres de tu malla deben tener conectividad entre todos los pods antes de configurar Cloud Service Mesh. Además, si unes clústeres que no están en el mismo proyecto, deben registrarse en el mismo proyecto de host de flota y los clústeres deben estar en una configuración de VPC compartida en la misma red. También te recomendamos que tengas un proyecto para alojar la VPC compartida y dos proyectos de servicio para crear clústeres. Para obtener más información, consulta Configurar clústeres con una VPC compartida.
  • Si usas el servicio de autoridad de certificación, todos los clústeres deben tener sus respectivas cadenas de grupos de AC subordinadas al mismo grupo de AC raíz. De lo contrario, todos ellos deberán usar el mismo grupo de CAs.

Definir variables de proyecto y de clúster

  1. Crea las siguientes variables de entorno para el ID del proyecto, la zona o la región del clúster, el nombre del clúster y el 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. Si se trata de clústeres recién creados, asegúrate de obtener las credenciales de cada clúster con los siguientes comandos gcloud. De lo contrario, los context asociados no estarán disponibles para usarse en los siguientes pasos 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}
    

    Por zonas

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

Crear regla de cortafuegos

En algunos casos, debe crear una regla de cortafuegos para permitir el tráfico entre clústeres. Por ejemplo, debes crear una regla de cortafuegos si:

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

GKE añade automáticamente reglas de cortafuegos 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 cortafuegos para permitir el tráfico entre subredes. Debes añadir una nueva regla de cortafuegos para cada subred con el fin de permitir los bloques CIDR de IP de origen 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 quieres exponer, usa el comando de 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 de 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 cortafuegos.

    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
    

Configurar el descubrimiento de endpoints

Habilitar la detección de endpoints entre clústeres públicos o privados con la API declarativa

Si habilitas Cloud Service Mesh gestionado con la API de flota, se habilitará la detección de endpoints en este clúster. Si has aprovisionado Cloud Service Mesh gestionado con otra herramienta, puedes habilitar manualmente la detección de endpoints en clústeres públicos o privados de una flota aplicando la configuración "multicluster_mode":"connected" en el configmap asm-options. Los clústeres que tengan esta configuración habilitada en la misma flota tendrán habilitada automáticamente la detección de servicios entre clústeres.

Esta es la única forma de configurar el descubrimiento de endpoints multiclúster si tienes la implementación del plano de control gestionada (TD) y la forma recomendada de configurarlo si tienes la implementación gestionada (Istiod).

Antes de continuar, debe crear una regla de cortafuegos.

Habilitar

Si el configmap asm-options ya existe en tu clúster, habilita la detección de endpoints del clúster:

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

Si el asm-options configmap aún no existe en tu clúster, créalo con los datos asociados y habilita la detección de endpoints para el clúster:

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

Inhabilitar

Para inhabilitar la detección de endpoints en un clúster, haz lo siguiente:

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

Si anulas el registro de un clúster de la flota sin inhabilitar el descubrimiento de endpoints, es posible que los secretos permanezcan en el clúster. Debes eliminar manualmente los secretos restantes.

  1. Ejecuta el siguiente comando para buscar secretos que requieran limpieza:

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

    kubectl delete secret SECRET_NAME
    

    Repite este paso con cada secreto restante.

Verificar la conectividad entre clústeres

En esta sección se explica cómo desplegar los servicios de ejemplo HelloWorld y Sleep en tu entorno multiclúster para verificar que el balanceo de carga entre clústeres funciona.

Definir la variable del directorio de muestras

  1. Ve a la ubicación donde se descargó asmcli y ejecuta el siguiente comando para definir ASM_VERSION:

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

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

Habilitar la inyección de sidecar

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

    for CTX in ${CTX_1} ${CTX_2}
    do
        kubectl create --context=${CTX} namespace sample
    done
    
  2. Habilita el espacio de nombres para la inyección. Los pasos dependen de la implementación del plano de control.

    Gestionado (TD)

    1. Aplica la etiqueta de inyecció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
    

    Gestionado (Istiod)

    Recomendación: Ejecuta el siguiente comando para aplicar la etiqueta de inyecció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
    

    Si ya eres usuario del plano de control de Istiod gestionado: Te recomendamos que utilices la inyección predeterminada, pero también se admite la inyección basada en revisiones. Sigue estas instrucciones:

    1. Ejecuta el siguiente comando para localizar los canales de lanzamiento disponibles:

      kubectl -n istio-system get controlplanerevision
      

      El resultado debería ser similar al siguiente:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      En el resultado, el valor de la columna NAME es la etiqueta de revisión que corresponde al canal de lanzamiento disponible para la versión de Cloud Service Mesh.

    2. Aplica la etiqueta de revisión al espacio de nombres:

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

Instalar 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
    

Desplegar HelloWorld v1 y v2 en cada clúster

  1. Implementa HelloWorld v1 en CLUSTER_1 y v2 en CLUSTER_2, lo que te ayudará más adelante a verificar el balanceo de carga 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. Confirma que HelloWorld v1 y v2 se están ejecutando con los siguientes comandos. Comprueba que el resultado sea similar al que se muestra:

    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

Desplegar el servicio de sueño

  1. Despliega el servicio Sleep en ambos clústeres. Este pod 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. Comprueba que el resultado sea similar al que se muestra:

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

Llama al servicio HelloWorld varias veces y comprueba el resultado para verificar respuestas alternas de las versiones 1 y 2:

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

    La salida es similar a la que se muestra a continuación:

    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'
    

    La salida es similar a la que se muestra a continuación:

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

Enhorabuena, has verificado tu malla de servicios de Cloud con balanceo de carga y varios clústeres.

Limpiar el servicio HelloWorld

Cuando termines de verificar el balanceo de carga, elimina el servicio HelloWorld y Sleep de tu clúster.

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