Configurar una malla de varios clústeres en GKE
En esta guía se explica cómo unir dos clústeres en una sola malla de servicios de Cloud mediante Mesh CA o Istio CA 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 versión 1.11 o posterior instalado en los clústeres que usan
asmcli install
. Necesitasasmcli
, la herramientaistioctl
y muestras queasmcli
descarga en el directorio que especificaste en--output_dir
al ejecutarasmcli install
. Si necesitas configurarlo, sigue los pasos que se indican en Instalar herramientas dependientes y validar el clúster para hacer lo siguiente: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 la AC de Istio, utiliza el mismo certificado raíz personalizado en ambos clústeres.
Si tu malla de servicios de Cloud se basa en clústeres privados, te recomendamos que crees una sola subred en la misma VPC. De lo contrario, debes asegurarte de que:
- Los planos de control pueden acceder a los planos de control de clústeres privados remotos a través de las IPs privadas del clúster.
- Puedes añadir los intervalos de IPs de los planos de control de llamadas a las redes autorizadas de los clústeres privados remotos. Para obtener más información, consulta el artículo Configurar el descubrimiento de endpoints entre clústeres privados.
El servidor de la API debe ser accesible para las demás instancias del plano de control de Cloud Service Mesh en la malla multiclúster.
- Asegúrate de que los clústeres tengan habilitado el acceso global.
- Asegúrate de que la IP del plano de control de Cloud Service Mesh se haya permitido correctamente a través de la lista de permitidos con la red autorizada principal.
Definir variables de proyecto y de clúster
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}"
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, loscontext
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
.
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}"))
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
Los pasos necesarios para configurar el descubrimiento de endpoints dependen de si prefieres usar la API declarativa en los clústeres de una flota o habilitarla manualmente en clústeres públicos o clústeres privados.
Habilitar la detección de endpoints entre clústeres públicos o privados con la API declarativa (vista previa)
Para habilitar la detección de endpoints en clústeres públicos o privados de una flota, aplica 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.
Este método está disponible para las instalaciones gestionadas de Cloud Service Mesh en todos los canales de lanzamiento. Esta es también la forma preferida de configurar el descubrimiento de endpoints multiclúster si has aprovisionado Cloud Service Mesh gestionado mediante la función Habilitar Cloud Service Mesh al crear un clúster de GKE en la Google Cloud consola.
Antes de continuar, debe crear una regla de cortafuegos.
Si tienes varios proyectos, debes añadir manualmente FLEET_PROJECT_ID.svc.id.goog
a trustDomainAliases
en el meshConfig
de la revisión si aún no lo has hecho.
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.
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
Elimina cada secreto:
kubectl delete secret SECRET_NAME -n istio-system
Repite este paso con cada secreto restante.
Configurar el descubrimiento de endpoints entre clústeres públicos
Para configurar el descubrimiento de endpoints entre clústeres de GKE, ejecuta
asmcli create-mesh
. Este comando:
- 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 de cada clúster o la ruta del archivo kubeconfig.
URI del clúster
En el siguiente comando, sustituye FLEET_PROJECT_ID
por el ID del proyecto host de la flota y el URI del clúster por el nombre del clúster, la zona o la región, y el ID del proyecto de cada clúster.
En este ejemplo solo se muestran dos clústeres, pero puedes ejecutar el comando para habilitar la detección de endpoints en otros clústeres, siempre que no superes el número máximo de clústeres que puedes añadir 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, sustituye FLEET_PROJECT_ID
por el ID del proyecto host de la flota y PATH_TO_KUBECONFIG
por la ruta de cada archivo kubeconfig
. En este ejemplo solo se muestran dos clústeres, pero puedes ejecutar el comando para habilitar la detección de endpoints en otros clústeres, siempre que no superes el número máximo de clústeres que puedes añadir a tu flota.
./asmcli create-mesh \
FLEET_PROJECT_ID \
PATH_TO_KUBECONFIG_1 \
PATH_TO_KUBECONFIG_2
Configurar el descubrimiento de endpoints entre clústeres privados
Configura los secretos remotos para permitir que el servidor de la API acceda al plano de control de Cloud Service Mesh del otro clúster. Los comandos dependen del tipo de Cloud Service Mesh (en el clúster o gestionado):
A. En el caso de Cloud Service Mesh en el clúster, debes configurar las IPs privadas en lugar de las públicas, ya que no se puede acceder a las IPs 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. En el caso de Cloud Service Mesh gestionado:
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
Aplica los nuevos secretos a los clústeres:
kubectl apply -f ${CTX_1}.secret --context=${CTX_2}
kubectl apply -f ${CTX_2}.secret --context=${CTX_1}
Configurar redes autorizadas en clústeres privados
Sigue las instrucciones de esta sección solo si se cumplen todas las condiciones siguientes en tu malla:
- Estás usando clústeres privados.
- Los clústeres no pertenecen a la misma subred.
- Los clústeres tienen habilitadas las redes autorizadas.
Cuando se despliegan varios clústeres privados, el plano de control de Cloud Service Mesh de cada clúster debe llamar al plano de control de GKE de los clústeres remotos. Para permitir el tráfico, debe añadir el intervalo de direcciones de los pods del clúster de llamada a las redes autorizadas de los clústeres remotos.
Obtén el bloque CIDR de IP de los pods de 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)"`
Añade los bloques CIDR de IP de los pods del 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 Crear un clúster con redes autorizadas.
Verifica que las redes autorizadas se hayan actualizado:
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)"
Habilitar el acceso global al plano de control
Sigue las instrucciones de esta sección solo si se cumplen todas las condiciones siguientes en tu malla:
- Estás usando clústeres privados.
- Utilizas diferentes regiones 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 de cada clúster llame al plano de control de GKE de los clústeres remotos.
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
Comprueba 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}
En la sección
privateClusterConfig
de la salida se muestra el estado demasterGlobalAccessConfig
.
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
Ve a la ubicación donde se descargó
asmcli
y ejecuta el siguiente comando para definirASM_VERSION
:export ASM_VERSION="$(./asmcli --version)"
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 comandoasmcli install
. En el siguiente comando, cambiaOUTPUT_DIR
por el directorio que hayas especificado en--output_dir
.export SAMPLES_DIR=OUTPUT_DIR/istio-${ASM_VERSION%+*}
Habilitar la inyección de sidecar
Busca el valor de la etiqueta de revisión, que usarás en pasos posteriores. El paso depende del tipo de Cloud Service Mesh (gestionado o en el clúster).
gestionados
Usa el siguiente comando para localizar la etiqueta de revisión, que usarás en pasos posteriores.
kubectl get controlplanerevision -n istio-system
El resultado es similar al siguiente:
NAME RECONCILED STALLED AGE asm-managed-rapid True False 89d
En la salida, en la columna
NAME
, anote el valor de la etiqueta de revisión. En este ejemplo, el valor esasm-managed-rapid
. Usa el valor de revisión en los pasos de la siguiente sección.En el clúster
Usa el siguiente comando para localizar la etiqueta de revisión, que usarás en pasos posteriores.
kubectl -n istio-system get pods -l app=istiod --show-labels
El resultado es similar al siguiente:
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
En el resultado, en la columna
LABELS
, anote el valor de la etiqueta de revisiónistiod
que sigue al prefijoistio.io/rev=
. En este ejemplo, el valor esasm-173-3
. Usa el valor de revisión en los pasos de la siguiente sección.
Instalar el servicio HelloWorld
Crea el espacio de nombres de ejemplo y la definición de servicio en cada clúster. En el siguiente comando, sustituye REVISION por la
istiod
etiqueta de revisión que has anotado en el paso 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
donde REVISION es la etiqueta de revisión
istiod
que has indicado anteriormente.El resultado es el siguiente:
label "istio-injection" not found. namespace/sample labeled
Puedes ignorar
label "istio-injection" not found.
sin problemaCrea 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
Implementa
HelloWorld v1
enCLUSTER_1
yv2
enCLUSTER_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
Confirma que
HelloWorld v1
yv2
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
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
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:
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 ...
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}