En este documento se explica un ejemplo práctico para desplegar una puerta de enlace externa multiclúster con el fin de enrutar el tráfico de Internet a una aplicación que se ejecuta en dos clústeres de GKE diferentes.
Las pasarelas de varios clústeres ofrecen una forma eficaz de gestionar el tráfico de los servicios desplegados en varios clústeres de GKE. Si usas la infraestructura de balanceo de carga global de Google, puedes crear un único punto de entrada para tus aplicaciones, lo que simplifica la gestión y mejora la fiabilidad.En este tutorial, usarás una aplicación store de ejemplo para simular una situación real en la que un servicio de compras online es propiedad de equipos independientes y está gestionado por ellos, y se despliega en una flota de clústeres de GKE compartidos.
Antes de empezar
Las pasarelas multiclúster requieren cierta preparación del entorno antes de poder implementarse. Antes de continuar, sigue los pasos que se indican en el artículo Preparar el entorno para usar Gateways multiclúster:
Despliega clústeres de GKE.
Registra tus clústeres en una flota (si aún no lo has hecho).
Habilita los controladores de servicio y de pasarela de varios clústeres.
Por último, consulta las limitaciones y los problemas conocidos del controlador de Gateway de GKE antes de usarlo en tu entorno.
Pasarela externa multiclúster y multirregional
En este tutorial, crearás una pasarela externa multiclúster que sirva tráfico externo a una aplicación que se ejecuta en dos clústeres de GKE.
En los siguientes pasos, debes hacer lo siguiente:
- Despliega la aplicación de ejemplo
storeen los clústeresgke-west-1ygke-east-1. - Configura los servicios de cada clúster que quieras exportar a tu flota (servicios de varios clústeres).
- Despliega una pasarela externa multiclúster y una HTTPRoute
en tu clúster de configuración (
gke-west-1).
Una vez que se hayan desplegado los recursos de aplicación y de puerta de enlace, podrás controlar el tráfico entre los dos clústeres de GKE mediante el enrutamiento basado en rutas:
- Las solicitudes a
/westse enrutan a los pods destoreen el clústergke-west-1. - Las solicitudes a
/eastse enrutan a los pods destoredel clústergke-east-1. - Las solicitudes a cualquier otra ruta se dirigen a uno de los clústeres en función de su estado, capacidad y proximidad al cliente que realiza la solicitud.
Desplegar la aplicación de demostración
Crea el
storeDeployment y el Namespace en los tres clústeres que se desplegaron en Prepara tu entorno para las pasarelas de varios clústeres:kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yamlDespliega los siguientes recursos en cada clúster:
namespace/store created deployment.apps/store createdEn todos los ejemplos de esta página se usa la aplicación implementada en este paso. Asegúrate de que la aplicación se haya implementado en los tres clústeres antes de probar cualquiera de los pasos restantes. En este ejemplo solo se usan los clústeres
gke-west-1ygke-east-1, mientras quegke-west-2se usa en otro ejemplo.
Servicios de varios clústeres
Los servicios son la forma en que los pods se exponen a los clientes. Como el controlador de Gateway de GKE usa el balanceo de carga nativo de contenedores, no usa ClusterIP ni el balanceo de carga de Kubernetes para acceder a los pods. El tráfico se envía directamente del balanceador de carga a las direcciones IP de los pods. Sin embargo, los servicios siguen desempeñando un papel fundamental como identificador lógico para agrupar pods.
Servicios multiclúster (MCS) es un estándar de API para los servicios que abarcan clústeres. Su controlador de GKE proporciona el descubrimiento de servicios en clústeres de GKE. El controlador de Gateway multiclúster usa recursos de la API MCS para agrupar pods en un servicio al que se puede acceder en varios clústeres o que abarca varios clústeres.
La API de servicios de varios clústeres define los siguientes recursos personalizados:
- Los ServiceExports se asignan a un servicio de Kubernetes y exportan los endpoints de ese servicio a todos los clústeres registrados en la flota. Cuando un servicio tiene un ServiceExport correspondiente, significa que se puede acceder a él mediante una pasarela de varios clústeres.
- El controlador de servicios multiclúster genera automáticamente los ServiceImports. ServiceExport y ServiceImport van en pares. Si existe un ServiceExport en la flota, se crea un ServiceImport correspondiente para permitir que se acceda al servicio asignado al ServiceExport desde todos los clústeres.
Exporting Services funciona de la siguiente manera: Existe un servicio de tienda en gke-west-1 que selecciona un grupo de pods en ese clúster. Se crea un ServiceExport en el clúster, lo que permite que los pods de gke-west-1 sean accesibles desde los otros clústeres de la flota. ServiceExport asigna y expone los servicios que tienen el mismo nombre y espacio de nombres que el recurso ServiceExport.
apiVersion: v1
kind: Service
metadata:
name: store
namespace: store
spec:
selector:
app: store
ports:
- port: 8080
targetPort: 8080
---
kind: ServiceExport
apiVersion: net.gke.io/v1
metadata:
name: store
namespace: store
En el siguiente diagrama se muestra lo que ocurre después de implementar un ServiceExport. Si existe un par ServiceExport y Service, el controlador de servicio de varios clústeres desplegará un ServiceImport correspondiente en cada clúster de GKE de la flota. ServiceImport es la representación local del store servicio
en cada clúster. De esta forma, el pod client de gke-east-1 puede usar ClusterIP o servicios sin encabezado para acceder a los pods store de gke-west-1. Cuando se usan de esta forma, los servicios multiclúster proporcionan balanceo de carga este-oeste entre clústeres sin necesidad de un servicio LoadBalancer interno.
Para usar servicios de varios clústeres en el balanceo de carga entre clústeres, consulta Configurar servicios de varios clústeres.
Las pasarelas de varios clústeres también usan ServiceImports, pero no para el balanceo de carga entre clústeres. En su lugar, las pasarelas usan ServiceImports como identificadores lógicos de un servicio que existe en otro clúster o que se extiende por varios clústeres. El siguiente HTTPRoute hace referencia a un ServiceImport en lugar de a un recurso Service. Al hacer referencia a un ServiceImport, se indica que está reenviando tráfico a un grupo de pods de backend que se ejecutan en uno o varios clústeres.
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: store-route
namespace: store
labels:
gateway: multi-cluster-gateway
spec:
parentRefs:
- kind: Gateway
namespace: store
name: external-http
hostnames:
- "store.example.com"
rules:
- backendRefs:
- group: net.gke.io
kind: ServiceImport
name: store
port: 8080
En el siguiente diagrama se muestra cómo la ruta HTTP store.example.com dirige el tráfico a los pods store de gke-west-1 y gke-east-1. El balanceador de carga los trata como un único grupo de backends. Si los pods de uno de los clústeres no están en buen estado, no se puede acceder a ellos o no tienen capacidad de tráfico, la carga de tráfico se equilibra entre los pods restantes del otro clúster. Se pueden añadir o quitar clústeres con los servicios store y ServiceExport. De esta forma, se añaden o se quitan Pods de backend de forma transparente sin necesidad de hacer cambios explícitos en la configuración de enrutamiento.
Exportación de servicios
En este punto, la aplicación se ejecuta en ambos clústeres. A continuación, expone y exporta las aplicaciones desplegando Services y ServiceExports en cada clúster.
Aplica el siguiente manifiesto al clúster
gke-west-1para crear los serviciosstoreystore-west-1, así como los ServiceExports:cat << EOF | kubectl apply --context gke-west-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-west-1 namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-west-1 namespace: store EOFAplica el siguiente manifiesto al clúster
gke-east-1para crear los serviciosstoreystore-east-1, así como los ServiceExports:cat << EOF | kubectl apply --context gke-east-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-east-1 namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-east-1 namespace: store EOFVerifica que se hayan creado los ServiceExports correctos en los clústeres.
kubectl get serviceexports --context CLUSTER_NAME --namespace storeReemplaza CLUSTER_NAME por
gke-west-1ygke-east-1. La salida es similar a la siguiente:# gke-west-1 NAME AGE store 2m40s store-west-1 2m40s # gke-east-1 NAME AGE store 2m25s store-east-1 2m25sEl resultado muestra que el servicio
storecontienestorepods en ambos clústeres, y que los serviciosstore-west-1ystore-east-1solo contienenstorepods en sus respectivos clústeres. Estos servicios superpuestos se usan para orientar los pods en varios clústeres o en un subconjunto de pods de un solo clúster.Después de unos minutos, comprueba que el controlador de servicios multiclúster ha creado automáticamente los
ServiceImportscorrespondientes en todos los clústeres de la flota.kubectl get serviceimports --context CLUSTER_NAME --namespace storeReemplaza CLUSTER_NAME por
gke-west-1ygke-east-1. La salida debería ser similar a la siguiente:# gke-west-1 NAME TYPE IP AGE store ClusterSetIP ["10.112.31.15"] 6m54s store-east-1 ClusterSetIP ["10.112.26.235"] 5m49s store-west-1 ClusterSetIP ["10.112.16.112"] 6m54s # gke-east-1 NAME TYPE IP AGE store ClusterSetIP ["10.72.28.226"] 5d10h store-east-1 ClusterSetIP ["10.72.19.177"] 5d10h store-west-1 ClusterSetIP ["10.72.28.68"] 4h32mEsto demuestra que se puede acceder a los tres servicios desde ambos clústeres de la flota. Sin embargo, como solo hay un clúster de configuración activo por flota, solo puedes implementar Gateways y HTTPRoutes que hagan referencia a estos ServiceImports en
gke-west-1. Cuando un HTTPRoute del clúster de configuración hace referencia a estos ServiceImports como back-ends, la Gateway puede reenviar el tráfico a estos Services independientemente del clúster desde el que se exporten.
Desplegar la pasarela y HTTPRoute
Una vez que se hayan desplegado las aplicaciones, puedes configurar una pasarela con gke-l7-global-external-managed-mc GatewayClass. Esta pasarela crea un balanceador de carga de aplicación externo configurado para distribuir el tráfico entre los clústeres de destino.
Aplica el siguiente manifiesto
Gatewayal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: external-http namespace: store spec: gatewayClassName: gke-l7-global-external-managed-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOFEsta configuración de Gateway implementa recursos de balanceador de carga de aplicación externo con la siguiente convención de nomenclatura:
gkemcg1-NAMESPACE-GATEWAY_NAME-HASH.Los recursos predeterminados que se crean con esta configuración son los siguientes:
- 1 balanceador de carga:
gkemcg1-store-external-http-HASH - 1 dirección IP pública:
gkemcg1-store-external-http-HASH - 1 regla de reenvío:
gkemcg1-store-external-http-HASH - 2 servicios de backend:
- Servicio de backend 404 predeterminado:
gkemcg1-store-gw-serve404-HASH - Servicio de backend predeterminado 500:
gkemcg1-store-gw-serve500-HASH
- Servicio de backend 404 predeterminado:
- 1 comprobación del estado:
- Comprobación del estado 404 predeterminada:
gkemcg1-store-gw-serve404-HASH
- Comprobación del estado 404 predeterminada:
- 0 reglas de enrutamiento (URLmap está vacío)
En esta fase, cualquier solicitud a GATEWAY_IP:80 muestra una página predeterminada con el siguiente mensaje:
fault filter abort.- 1 balanceador de carga:
Aplica el siguiente manifiesto
HTTPRouteal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: public-store-route namespace: store labels: gateway: external-http spec: hostnames: - "store.example.com" parentRefs: - name: external-http rules: - matches: - path: type: PathPrefix value: /west backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-1 port: 8080 - matches: - path: type: PathPrefix value: /east backendRefs: - group: net.gke.io kind: ServiceImport name: store-east-1 port: 8080 - backendRefs: - group: net.gke.io kind: ServiceImport name: store port: 8080 EOFEn esta fase, cualquier solicitud a GATEWAY_IP:80 muestra una página predeterminada con el siguiente mensaje:
fault filter abort.Después de la implementación, este HTTPRoute configura el siguiente comportamiento de enrutamiento:
- Las solicitudes a
/westse enrutan a los podsstoredel clústergke-west-1, ya que los pods seleccionados porstore-west-1ServiceExport solo existen en el clústergke-west-1. - Las solicitudes a
/eastse enrutan a los podsstoredel clústergke-east-1, ya que los pods seleccionados porstore-east-1ServiceExport solo existen en el clústergke-east-1. - Las solicitudes a cualquier otra ruta se dirigen a los pods
storede cualquiera de los clústeres, según su estado, capacidad y proximidad al cliente que realiza la solicitud. - Las solicitudes a GATEWAY_IP:80 dan como resultado una página predeterminada que muestra el siguiente mensaje:
fault filter abort.
Ten en cuenta que, si todos los pods de un clúster determinado no están en buen estado (o no existen), el tráfico al servicio
storesolo se enviará a los clústeres que tengan podsstore. La existencia de un ServiceExport y un Service en un clúster determinado no garantiza que se envíe tráfico a ese clúster. Los pods deben existir y responder afirmativamente a la comprobación de estado del balanceador de carga. De lo contrario, el balanceador de carga solo enviará tráfico a losstorepods en buen estado de otros clústeres.Los recursos se crean con esta configuración:
- 3 servicios de backend:
- El servicio de backend
store:gkemcg1-store-store-8080-HASH - El servicio de backend
store-east-1:gkemcg1-store-store-east-1-8080-HASH - El servicio de backend
store-west-1:gkemcg1-store-store-west-1-8080-HASH
- El servicio de backend
- 3 comprobaciones del estado:
- Comprobación del estado de
store:gkemcg1-store-store-8080-HASH - Comprobación del estado de
store-east-1:gkemcg1-store-store-east-1-8080-HASH - Comprobación del estado de
store-west-1:gkemcg1-store-store-west-1-8080-HASH
- Comprobación del estado de
- 1 regla de enrutamiento en el mapa de URLs:
- La regla de enrutamiento
store.example.com: - 1 anfitrión:
store.example.com - Varias
matchRulespara enrutar al nuevo servicio de backend
- La regla de enrutamiento
- Las solicitudes a
En el siguiente diagrama se muestran los recursos que has implementado en ambos clústeres.
Como gke-west-1 es el clúster de configuración de Gateway, es el clúster en el que el controlador de Gateway monitoriza Gateway, HTTPRoutes y ServiceImports. Cada clúster tiene un store ServiceImport y otro ServiceImport específico de ese clúster. Ambos apuntan a los mismos pods. De esta forma, HTTPRoute puede especificar exactamente a dónde debe ir el tráfico: a los store pods
de un clúster específico o a los store pods de todos los clústeres.
Ten en cuenta que se trata de un modelo de recursos lógico, no de una representación del flujo de tráfico. La ruta del tráfico va directamente del balanceador de carga a los pods de backend y no tiene ninguna relación directa con el clúster de configuración.
Validar la implementación
Ahora puedes enviar solicitudes a nuestra puerta de enlace multiclúster y distribuir el tráfico entre ambos clústeres de GKE.
Valida que Gateway y HTTPRoute se han implementado correctamente inspeccionando el estado y los eventos de Gateway.
kubectl describe gateways.gateway.networking.k8s.io external-http --context gke-west-1 --namespace storeLa salida debería ser similar a la siguiente:
Name: external-http Namespace: store Labels: <none> Annotations: networking.gke.io/addresses: /projects/PROJECT_NUMBER/global/addresses/gkemcg1-store-external-http-laup24msshu4 networking.gke.io/backend-services: /projects/PROJECT_NUMBER/global/backendServices/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/backendServices/gke... networking.gke.io/firewalls: /projects/PROJECT_NUMBER/global/firewalls/gkemcg1-l7-default-global networking.gke.io/forwarding-rules: /projects/PROJECT_NUMBER/global/forwardingRules/gkemcg1-store-external-http-a5et3e3itxsv networking.gke.io/health-checks: /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-store-gw-serve404-80-n65xmts4xvw2, /projects/PROJECT_NUMBER/global/healthChecks/gkemcg1-s... networking.gke.io/last-reconcile-time: 2023-10-12T17:54:24Z networking.gke.io/ssl-certificates: networking.gke.io/target-http-proxies: /projects/PROJECT_NUMBER/global/targetHttpProxies/gkemcg1-store-external-http-94oqhkftu5yz networking.gke.io/target-https-proxies: networking.gke.io/url-maps: /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-store-external-http-94oqhkftu5yz API Version: gateway.networking.k8s.io/v1 Kind: Gateway Metadata: Creation Timestamp: 2023-10-12T06:59:32Z Finalizers: gateway.finalizer.networking.gke.io Generation: 1 Resource Version: 467057 UID: 1dcb188e-2917-404f-9945-5f3c2e907b4c Spec: Gateway Class Name: gke-l7-global-external-managed-mc Listeners: Allowed Routes: Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Namespaces: From: Same Name: http Port: 80 Protocol: HTTP Status: Addresses: Type: IPAddress Value: 34.36.127.249 Conditions: Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has deprecated this condition, do not depend on it. Observed Generation: 1 Reason: Scheduled Status: True Type: Scheduled Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead. Observed Generation: 1 Reason: Ready Status: True Type: Ready Listeners: Attached Routes: 1 Conditions: Last Transition Time: 2023-10-12T07:00:41Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T07:00:41Z Message: The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead. Observed Generation: 1 Reason: Ready Status: True Type: Ready Name: http Supported Kinds: Group: gateway.networking.k8s.io Kind: HTTPRoute Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal UPDATE 35m (x4 over 10h) mc-gateway-controller store/external-http Normal SYNC 4m22s (x216 over 10h) mc-gateway-controller SYNC on store/external-http was a successUna vez que la pasarela se haya implementado correctamente, obtén la dirección IP externa de
external-httpGateway.kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace storeSustituye
VIPen los pasos siguientes por la dirección IP que recibas como resultado.Envía tráfico a la ruta raíz del dominio. De esta forma, se equilibra la carga del tráfico al
storeServiceImport, que se encuentra en los clústeresgke-west-1ygke-east-1. El balanceador de carga envía el tráfico a la región más cercana y es posible que no veas respuestas de la otra región.curl -H "host: store.example.com" http://VIPEl resultado confirma que la solicitud la ha atendido el pod del clúster
gke-east-1:{ "cluster_name": "gke-east-1", "zone": "us-east1-b", "host_header": "store.example.com", "node_name": "gke-gke-east-1-default-pool-7aa30992-t2lp.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-dg22z", "pod_name_emoji": "⏭", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:32:51" }A continuación, envía tráfico a la ruta
/west. De esta forma, se dirige el tráfico alstore-west-1ServiceImportgke-west-1, que solo tiene pods que se ejecutan en el clúster. Un ServiceImport específico de un clúster, comostore-west-1, permite que el propietario de una aplicación envíe tráfico explícitamente a un clúster concreto, en lugar de dejar que el balanceador de carga tome la decisión.curl -H "host: store.example.com" http://VIP/westEl resultado confirma que la solicitud la ha atendido el pod del clúster
gke-west-1:{ "cluster_name": "gke-west-1", "zone": "us-west1-a", "host_header": "store.example.com", "node_name": "gke-gke-west-1-default-pool-65059399-2f41.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-d25m5", "pod_name_emoji": "🍾", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:39:15", }Por último, envía tráfico a la ruta
/east.curl -H "host: store.example.com" http://VIP/eastEl resultado confirma que la solicitud la ha atendido el pod del clúster
gke-east-1:{ "cluster_name": "gke-east-1", "zone": "us-east1-b", "host_header": "store.example.com", "node_name": "gke-gke-east-1-default-pool-7aa30992-7j7z.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-hz6mw", "pod_name_emoji": "🧜🏾", "project_id": "agmsb-k8s", "timestamp": "2021-06-01T17:40:48" }
Limpieza
Después de completar los ejercicios de este documento, siga estos pasos para quitar recursos y evitar que se apliquen cargos no deseados a su cuenta:
Anula el registro de los clústeres de la flota si no es necesario que estén registrados para otro propósito.
Para inhabilitar la función
multiclusterservicediscovery, sigue estos pasos:gcloud container fleet multi-cluster-services disableInhabilita la entrada de varios clústeres:
gcloud container fleet ingress disableInhabilita las APIs:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
Solución de problemas
No hay upstream en buen estado
Síntoma:
El siguiente problema puede producirse cuando crea una pasarela, pero no puede acceder a los servicios de backend (código de respuesta 503):
no healthy upstream
Motivo:
Este mensaje de error indica que el comprobador de estado no puede encontrar servicios de backend en buen estado. Es posible que tus servicios de backend estén en buen estado, pero que tengas que personalizar las comprobaciones del estado.
Solución alternativa:
Para solucionar este problema, personaliza la comprobación de estado según los requisitos de tu aplicación (por ejemplo, /health) mediante un HealthCheckPolicy.