En esta página se describe cómo desplegar recursos de Gateway de Kubernetes para equilibrar la carga del tráfico de entrada en varios clústeres (o flotas) de Google Kubernetes Engine (GKE). Antes de desplegar pasarelas de varios clústeres, consulta el artículo sobre cómo habilitar pasarelas de varios clústeres para preparar tu entorno.
Para desplegar pasarelas con el fin de balancear la carga del tráfico de entrada a un solo clúster de GKE, consulta Desplegar pasarelas.
Pasarelas de varios clústeres
Una pasarela de varios clústeres es un recurso de pasarela que balancea la carga del tráfico entre varios clústeres de Kubernetes. En GKE, las gke-l7-global-external-managed-mc
,
gke-l7-regional-external-managed-mc
, gke-l7-rilb-mc
y gke-l7-gxlb-mc
GatewayClasses implementan Gateways multiclúster que proporcionan enrutamiento HTTP, división de tráfico, creación de reflejo del tráfico, conmutación por error basada en el estado y más en diferentes clústeres de GKE, espacios de nombres de Kubernetes y regiones.
Las pasarelas de varios clústeres permiten a los administradores de infraestructura gestionar la red de aplicaciones en muchos clústeres y equipos de forma fácil, segura y escalable.
En esta página se presentan tres ejemplos para enseñarte a desplegar Gateways multiclúster mediante el controlador de Gateway de GKE:
- Ejemplo 1: una gateway externa de varios clústeres que proporciona balanceo de carga en dos clústeres de GKE para el tráfico de Internet.
- Ejemplo 2: Una puerta de enlace privada entre regiones de la capa 7.
- Ejemplo 3: División del tráfico basada en el peso y creación de réplicas del tráfico entre dos clústeres de GKE para el tráfico de VPC interno.
- Ejemplo 4: Una pasarela basada en la capacidad para balancear la carga de las solicitudes a diferentes back-ends en función de su capacidad máxima.
En cada uno de los ejemplos se usarán las mismas aplicaciones store y site para modelar un caso práctico en el que un servicio de compras online y un servicio de sitio web sean propiedad de equipos independientes y estén gestionados por ellos, y se implementen en una flota de clústeres de GKE compartidos. Cada ejemplo destaca diferentes topologías y casos prácticos que permiten las pasarelas de varios clústeres.
Las Multi-cluster Gateways requieren cierta preparación del entorno antes de poder implementarse. Antes de continuar, siga los pasos que se indican en Habilitar pasarelas de varios clústeres:
Despliega clústeres de GKE.
Registre sus clústeres en una flota.
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 en una aplicación que se ejecute en dos clústeres de GKE.
En los siguientes pasos, debes hacer lo siguiente:
- Despliega la aplicación de ejemplo
store
en los clústeresgke-west-1
ygke-east-1
. - Configura los servicios de cada clúster para que se exporten 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 de los dos clústeres de GKE mediante el enrutamiento basado en rutas:
- Las solicitudes a
/west
se enrutan a los pods destore
del clústergke-west-1
. - Las solicitudes a
/east
se enrutan a los pods destore
del 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 envía la solicitud.
Desplegar la aplicación de demostración
Crea el
store
Deployment y el Namespace en los tres clústeres que se desplegaron en Habilitar 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.yaml
Despliega los siguientes recursos en cada clúster:
namespace/store created deployment.apps/store created
En 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-1
ygke-east-1
, mientras quegke-west-2
se 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 parejas. 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 se asignará y expondrá a los servicios que tengan 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 para 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/v1beta1
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ñadirán o quitarán Pods de backend de forma transparente sin que tengas que hacer ningún cambio explícito 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, expondrá y exportará las aplicaciones desplegando Services y ServiceExports en cada clúster.
Aplica el siguiente manifiesto al clúster
gke-west-1
para crear los serviciosstore
ystore-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 EOF
Aplica el siguiente manifiesto al clúster
gke-east-1
para crear los serviciosstore
ystore-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 EOF
Verifica que se hayan creado los ServiceExports correctos en los clústeres.
kubectl get serviceexports --context CLUSTER_NAME --namespace store
Reemplaza CLUSTER_NAME por
gke-west-1
ygke-east-1
. La salida debería ser 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 2m25s
Esto demuestra que el servicio
store
contiene podsstore
en ambos clústeres, mientras que los serviciosstore-west-1
ystore-east-1
solo contienen podsstore
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
ServiceImports
correspondientes en todos los clústeres de la flota.kubectl get serviceimports --context CLUSTER_NAME --namespace store
Reemplaza CLUSTER_NAME por
gke-west-1
ygke-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"] 4h32m
Esto 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 la ruta HTTP
Una vez que se hayan desplegado las aplicaciones, puedes configurar una pasarela con la 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
Gateway
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 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 EOF
Esta 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 mostrará una página predeterminada con el siguiente mensaje:
fault filter abort
.- 1 balanceador de carga:
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 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 EOF
En esta fase, cualquier solicitud a GATEWAY_IP:80 mostrará una página predeterminada con el siguiente mensaje:
fault filter abort
.Una vez implementado, este HTTPRoute configurará el siguiente comportamiento de enrutamiento:
- Las solicitudes a
/west
se enrutan a los podsstore
del clústergke-west-1
, ya que los pods seleccionados porstore-west-1
ServiceExport solo existen en el clústergke-west-1
. - Las solicitudes a
/east
se enrutan a los podsstore
del clústergke-east-1
, ya que los pods seleccionados porstore-east-1
ServiceExport solo existen en el clústergke-east-1
. - Las solicitudes a cualquier otra ruta se dirigen a los pods
store
de cualquiera de los clústeres, según su estado, capacidad y proximidad al cliente que realiza la solicitud. - Las solicitudes a GATEWAY_IP:80 mostrarán una página predeterminada con 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
store
solo 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 los podsstore
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
matchRules
para 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 nuestros 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, la HTTPRoute puede especificar exactamente a dónde debe ir el tráfico: a los store
pods de un clúster concreto 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 store
La 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/v1beta1 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 success
Una vez que la pasarela se haya implementado correctamente, obtén la dirección IP externa de
external-http
Gateway.kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
Sustituye
VIP
en 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
store
ServiceImport, que se encuentra en los clústeresgke-west-1
ygke-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://VIP
El 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-1
ServiceImport, que solo tiene pods que se ejecutan en el clústergke-west-1
. 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 específico, en lugar de dejar que el balanceador de carga tome la decisión.curl -H "host: store.example.com" http://VIP/west
El 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/east
El 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" }
Desplegar una pasarela de varios clústeres interna en varias regiones
Puedes desplegar pasarelas de varios clústeres que proporcionen balanceo de carga interno de capa 7 en clústeres de GKE de varias regiones. Estas pasarelas usan gke-l7-cross-regional-internal-managed-mc
GatewayClass. Esta GatewayClass aprovisiona un balanceador de carga de aplicaciones interno entre regiones gestionado por Google Cloud que habilita IPs virtuales internas a las que pueden acceder los clientes de tu red de VPC. Puedes exponer estas pasarelas mediante front-ends en las regiones que elijas. Para ello, solo tienes que usar la pasarela para solicitar direcciones en esas regiones. La dirección IP virtual interna puede ser una sola dirección IP o direcciones IP de varias regiones, con una dirección IP por región especificada en la pasarela. El tráfico se dirige al clúster de GKE de backend en buen estado más cercano que pueda atender la solicitud.
Antes de empezar
Configura tu proyecto y shell configurando tu entorno
gcloud
con el ID de tu proyecto:export PROJECT_ID="YOUR_PROJECT_ID" gcloud config set project ${PROJECT_ID}
Crea clústeres de GKE en diferentes regiones.
En este ejemplo se usan dos clústeres:
gke-west-1
enus-west1
ygke-east-1
enus-east1
. Asegúrate de que la API Gateway esté habilitada (--gateway-api=standard
) y de que los clústeres estén registrados en una flota.gcloud container clusters create gke-west-1 \ --location=us-west1-a \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard gcloud container clusters create gke-east-1 \ --location=us-east1-c \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard
Cambiar el nombre de los contextos para acceder a ellos más fácilmente:
gcloud container clusters get-credentials gke-west-1 \ --location=us-west1-a \ --project=${PROJECT_ID} gcloud container clusters get-credentials gke-east-1 \ --location=us-east1-c \ --project=${PROJECT_ID} kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1 kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1
Habilita los servicios de varios clústeres (MCS) y la entrada de varios clústeres (MCI/Gateway):
gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID} # Set the config membership to one of your clusters (e.g., gke-west-1) # This cluster will be the source of truth for multi-cluster Gateway and Route resources. gcloud container fleet ingress enable \ --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \ --project=${PROJECT_ID}
Configura subredes de solo proxy. Se necesita una subred de solo proxy en cada región en la que se encuentren tus clústeres de GKE y en la que vaya a funcionar el balanceador de carga. Los balanceadores de carga de aplicación internos entre regiones requieren que el propósito de esta subred se defina como
GLOBAL_MANAGED_PROXY
.# Proxy-only subnet for us-west1 gcloud compute networks subnets create us-west1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-west1 \ --network=default \ --range=10.129.0.0/23 # Choose an appropriate unused CIDR range # Proxy-only subnet for us-east1 gcloud compute networks subnets create us-east1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-east1 \ --network=default \ --range=10.130.0.0/23 # Choose an appropriate unused CIDR range
Si no usas la red predeterminada, sustituye
default
por el nombre de tu red de VPC. Asegúrate de que los intervalos CIDR sean únicos y no se solapen.Despliega tus aplicaciones de demostración, como
store
, en ambos clústeres. El archivostore.yaml
de ejemplo degke-networking-recipes
crea un espacio de nombresstore
y una implementación.kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
Exporta los servicios de cada clúster creando recursos
Service
yServiceExport
de Kubernetes en cada clúster, lo que permite que los servicios se puedan descubrir en toda la flota. En el siguiente ejemplo se exportan un serviciostore
genérico y servicios específicos de la región (store-west-1
ystore-east-1
) de cada clúster, todos ellos en el espacio de nombresstore
.Aplicar a
gke-west1
:cat << EOF | kubectl apply --context gke-west1 -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 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-west-1 # Exporting the region-specific service namespace: store EOF
Aplicar a
gke-east1
:cat << EOF | kubectl apply --context gke-east1 -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 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-east-1 # Exporting the region-specific service namespace: store EOF
Comprueba ServiceImports: Verifica que se hayan creado recursos
ServiceImport
en cada clúster del espacio de nombresstore
. Puede que tarden unos minutos en crearse.bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store
Deberías verstore
,store-west-1
ystore-east-1
(o las entradas correspondientes en función de la propagación).
Configurar una pasarela interna multirregional
Define un recurso Gateway
que haga referencia a gke-l7-cross-regional-internal-managed-mc
GatewayClass. Aplica este manifiesto al clúster de configuración que hayas designado, como gke-west-1
.
El campo spec.addresses
te permite solicitar direcciones IP efímeras en regiones concretas o usar direcciones IP estáticas preasignadas.
Para usar direcciones IP efímeras, guarda el siguiente manifiesto
Gateway
comocross-regional-gateway.yaml
:# cross-regional-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-cross-region-gateway namespace: store # Namespace for the Gateway resource spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: # Addresses across regions. Address value is allowed to be empty or matching # the region name. - type: networking.gke.io/ephemeral-ipv4-address/us-west1 value: "us-west1" - type: networking.gke.io/ephemeral-ipv4-address/us-east1 value: "us-east1" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute # Only allow HTTPRoute to attach
En la siguiente lista se definen algunos de los campos del archivo YAML anterior:
metadata.namespace
: el espacio de nombres en el que se crea el recurso Gateway (por ejemplo,store
).spec.gatewayClassName
: el nombre de GatewayClass. Debe sergke-l7-cross-regional-internal-managed-mc
.spec.listeners.allowedRoutes.kinds
: los tipos de objetos Route que se pueden adjuntar. Por ejemplo,HTTPRoute
.spec.addresses
:type: networking.gke.io/ephemeral-ipv4-address/REGION
: solicita una dirección IP efímera.value
: especifica la región de la dirección; por ejemplo,"us-west1"
o"us-east1"
.
Aplica el manifiesto a tu clúster de configuración. Por ejemplo,
gke-west1
:kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
Asociar HTTPRoutes a la Gateway
Define los recursos de HTTPRoute
para gestionar el enrutamiento del tráfico y aplícalos a tu clúster de configuración.
Guarda el siguiente manifiesto
HTTPRoute
comostore-route.yaml
:# store-route.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store-route namespace: store labels: gateway: cross-regional-internal spec: parentRefs: - name: internal-cross-region-gateway namespace: store # Namespace where the Gateway is deployed hostnames: - "store.example.internal" # Hostname clients will use rules: - matches: # Rule for traffic to /west - path: type: PathPrefix value: /west backendRefs: - group: net.gke.io # Indicates a multi-cluster ServiceImport kind: ServiceImport name: store-west-1 # Targets the ServiceImport for the west cluster port: 8080 - matches: # Rule for traffic to /east - path: type: PathPrefix value: /east backendRefs: - group: net.gke.io kind: ServiceImport name: store-east-1 # Targets the ServiceImport for the east cluster port: 8080 - backendRefs: # Default rule for other paths (e.g., /) - group: net.gke.io kind: ServiceImport name: store # Targets the generic 'store' ServiceImport (any region) port: 8080
En la siguiente lista se definen algunos de los campos del archivo YAML anterior:
spec.parentRefs
: asocia esta ruta ainternal-cross-region-gateway
en el espacio de nombresstore
.spec.hostnames
: representa el nombre de host que usan los clientes para acceder al servicio.spec.rules
: define la lógica de enrutamiento. En este ejemplo se usa el enrutamiento basado en rutas:- El tráfico de
/west
se dirige a ServiceImport destore-west-1
. - El tráfico de
/east
se dirige a ServiceImport destore-east-1
. - El resto del tráfico, como
/
, se dirige al ServiceImport genéricostore
.
- El tráfico de
backendRefs
:group: net.gke.io
ykind: ServiceImport
se dirigen a servicios de varios clústeres.
Aplica el manifiesto
HTTPRoute
a tu clúster de configuración:kubectl apply --context gke-west1 -f store-route.yaml
Verificar el estado de la pasarela y la ruta
Comprueba el estado de la pasarela:
kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1
Busca una condición con el estado
type:
Programadoand
: "True". You should see IP addresses assigned in the
status.addressesfield, corresponding to the regions you specified (e.g., one for
us-west1and one for
us-east1`).Comprueba el estado de HTTPRoute:
kubectl get httproute store-route -n store -o yaml --context gke-west1
Busca una condición en
status.parents[].conditions
contype: Accepted
(oResolvedRefs
) ystatus: "True"
.
Confirmar el tráfico
Después de asignar las direcciones IP a la pasarela, puedes probar el tráfico desde una máquina virtual cliente que esté en tu red de VPC y en una de las regiones, o en una región que pueda conectarse a la dirección IP de la pasarela.
Recupera las direcciones IP de la pasarela.
El siguiente comando intenta analizar el resultado JSON. Es posible que tengas que ajustar el
jsonpath
en función de la estructura exacta.kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
El resultado de este comando debe incluir las IPs virtuales, como
VIP1_WEST
oVIP2_EAST
.Enviar solicitudes de prueba: Desde una VM cliente de tu VPC:
# Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1 # Traffic to /west should ideally be served by gke-west-1 curl -H "host: store.example.internal" http://VIP_WEST/west curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path # Traffic to /east should ideally be served by gke-east-1 curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path curl -H "host: store.example.internal" http://VIP_EAST/east # Traffic to / (default) could be served by either cluster curl -H "host: store.example.internal" http://VIP_WEST/ curl -H "host: store.example.internal" http://VIP_EAST/
La respuesta debe incluir detalles de la aplicación
store
que indiquen qué pod de backend ha servido la solicitud, comocluster_name
ozone
.
Usar direcciones IP estáticas
En lugar de direcciones IP efímeras, puedes usar direcciones IP internas estáticas preasignadas.
Crea direcciones IP estáticas en las regiones que quieras usar:
gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID} gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}
Si no usas la subred predeterminada, sustituye
default
por el nombre de la subred que tenga la dirección IP que quieras asignar. Estas subredes son subredes normales, no subredes de solo proxy.Actualiza el manifiesto de la pasarela modificando la sección
spec.addresses
de tu archivocross-regional-gateway.yaml
:# cross-regional-gateway-static-ip.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-cross-region-gateway # Or a new name if deploying alongside namespace: store spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: - type: networking.gke.io/named-address-with-region # Use for named static IP value: "regions/us-west1/addresses/cross-region-gw-ip-west" - type: networking.gke.io/named-address-with-region value: "regions/us-east1/addresses/cross-region-gw-ip-east" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute
Aplica el archivo de manifiesto de la pasarela actualizado.
kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
Consideraciones especiales para subredes no predeterminadas
Ten en cuenta lo siguiente cuando uses subredes no predeterminadas:
Misma red de VPC: todos los recursos creados por el usuario, como las direcciones IP estáticas, las subredes solo proxy y los clústeres de GKE, deben residir en la misma red de VPC.
Subred de direcciones: cuando creas direcciones IP estáticas para la pasarela, se asignan desde subredes normales de las regiones especificadas.
Nombres de subredes de clústeres: cada región debe tener una subred con el mismo nombre que la subred en la que se encuentra el clúster de configuración de MCG.
- Por ejemplo, si tu clúster de configuración
gke-west-1
está enprojects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet
, las regiones para las que solicitas direcciones también deben tener la subredmy-custom-subnet
. Si solicitas direcciones en las regionesus-east1
yus-centra1
, también debe haber una subred llamadamy-custom-subnet
en esas regiones.
- Por ejemplo, si tu clúster de configuración
Enrutamiento multiclúster azul-verde con Gateway
Las GatewayClasses gke-l7-global-external-managed-*
, gke-l7-regional-external-managed-*
y gke-l7-rilb-*
tienen muchas funciones avanzadas de enrutamiento del tráfico, como la división del tráfico, la coincidencia de encabezados, la manipulación de encabezados, la creación de reflejos del tráfico y más. En este ejemplo, se muestra cómo usar la división del tráfico basada en el peso para controlar explícitamente la proporción del tráfico entre dos clústeres de GKE.
En este ejemplo se describen algunos pasos realistas que seguiría un propietario de un servicio para mover o ampliar su aplicación a un nuevo clúster de GKE. El objetivo de los despliegues azul-verde es reducir el riesgo mediante varios pasos de validación que confirman que el nuevo clúster funciona correctamente. En este ejemplo se muestran cuatro fases de implementación:
- 100%-Canario basado en encabezados: Usa el enrutamiento de encabezados HTTP para enviar solo tráfico de prueba o sintético al nuevo clúster.
- 100% - Tráfico reflejado: Refleja el tráfico de usuarios al clúster canary. De esta forma, se prueba la capacidad del clúster canary copiando el 100% del tráfico de usuarios a este clúster.
- 90%-10%: Canary a traffic split del 10% para exponer lentamente el nuevo clúster al tráfico real.
- 0%-100%: Cambia por completo al nuevo clúster con la opción de volver al anterior si se detecta algún error.
Este ejemplo es similar al anterior, pero en él se implementa una pasarela interna multiclúster. De esta forma, se implementa un balanceador de carga de aplicaciones interno al que solo se puede acceder de forma privada desde la VPC. Usarás los clústeres y la misma aplicación que has desplegado en los pasos anteriores, pero los desplegarás a través de otra pasarela.
Requisitos previos
En el siguiente ejemplo se siguen algunos de los pasos que se indican en el artículo Desplegar una pasarela externa de varios clústeres. Asegúrate de que has seguido estos pasos antes de continuar con este ejemplo:
Desplegar una aplicación de demostración
En este ejemplo se usan los clústeres
gke-west-1
ygke-west-2
que ya has configurado. Estos clústeres están en la misma región porquegke-l7-rilb-mc
GatewayClass es regional y solo admite back-ends de clúster en la misma región.Despliega los elementos Service y ServiceExport necesarios en cada clúster. Si has implementado Services y ServiceExports del ejemplo anterior, ya habrás implementado algunos de estos.
kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-1-service.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-west-2-service.yaml
Despliega un conjunto de recursos similar en cada clúster:
service/store created serviceexport.net.gke.io/store created service/store-west-2 created serviceexport.net.gke.io/store-west-2 created
Configurar una subred de solo proxy
Si aún no lo ha hecho, configure una subred solo de proxy para cada región en la que vaya a implementar pasarelas internas. Esta subred se usa para proporcionar direcciones IP internas a los proxies del balanceador de carga y debe configurarse con un --purpose
definido como REGIONAL_MANAGED_PROXY
.
Debes crear una subred de solo proxy antes de crear las pasarelas que gestionan los balanceadores de carga de aplicaciones internos. Cada región de una red de nube privada virtual (VPC) en la que uses balanceadores de carga de aplicaciones internos debe tener una subred solo proxy.
El comando gcloud compute networks subnets create
crea una subred de solo proxy.
gcloud compute networks subnets create SUBNET_NAME \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=REGION \
--network=VPC_NETWORK_NAME \
--range=CIDR_RANGE
Haz los cambios siguientes:
SUBNET_NAME
: el nombre de la subred de solo proxy.REGION
: la región de la subred de solo proxy.VPC_NETWORK_NAME
: el nombre de la red de VPC que contiene la subred.CIDR_RANGE
: el intervalo de direcciones IP principal de la subred. Debes usar una máscara de subred que no sea superior a/26
para que haya al menos 64 direcciones IP disponibles para los proxies de la región. La máscara de subred recomendada es/23
.
Desplegar la pasarela
La siguiente pasarela se crea a partir de gke-l7-rilb-mc
GatewayClass, que es una pasarela interna regional que solo puede dirigirse a clústeres de GKE de la misma región.
Aplica el siguiente manifiesto
Gateway
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-http namespace: store spec: gatewayClassName: gke-l7-rilb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOF
Valida que la pasarela se haya iniciado correctamente. Puedes filtrar solo los eventos de esta pasarela con el siguiente comando:
kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
El despliegue de la pasarela se habrá realizado correctamente si el resultado es similar al siguiente:
LAST SEEN TYPE REASON OBJECT MESSAGE 5m18s Normal ADD gateway/internal-http store/internal-http 3m44s Normal UPDATE gateway/internal-http store/internal-http 3m9s Normal SYNC gateway/internal-http SYNC on store/internal-http was a success
Canary basado en encabezados
El lanzamiento de versiones canary basado en encabezados permite al propietario del servicio hacer coincidir el tráfico de prueba sintético que no procede de usuarios reales. Es una forma sencilla de validar que la red básica de la aplicación funciona sin exponer a los usuarios directamente.
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Matches for env=canary and sends it to store-west-2 ServiceImport - matches: - headers: - name: env value: canary backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 # All other traffic goes to store-west-1 ServiceImport - backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-1 port: 8080 EOF
Una vez implementado, este HTTPRoute configura el siguiente comportamiento de enrutamiento:
- Las solicitudes internas a
store.example.internal
sin el encabezado HTTPenv: canary
se dirigen a los podsstore
del clústergke-west-1
. - Las solicitudes internas a
store.example.internal
con el encabezado HTTPenv: canary
se dirigen a los podsstore
del clústergke-west-2
.
Valida que HTTPRoute funciona correctamente enviando tráfico a la dirección IP de Gateway.
- Las solicitudes internas a
Recupera la dirección IP interna de
internal-http
.kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
Sustituye VIP en los pasos siguientes por la dirección IP que recibas como resultado.
Envía una solicitud a la pasarela mediante el encabezado HTTP
env: canary
. De esta forma, se confirmará que el tráfico se está enrutando agke-west-2
. Usa un cliente privado en la misma VPC que los clústeres de GKE para confirmar que las solicitudes se enrutan correctamente. El siguiente comando debe ejecutarse en una máquina que tenga acceso privado a la dirección IP de la pasarela. De lo contrario, no funcionará.curl -H "host: store.example.internal" -H "env: canary" http://VIP
El resultado confirma que la solicitud la ha atendido un pod del clúster
gke-west-2
:{ "cluster_name": "gke-west-2", "host_header": "store.example.internal", "node_name": "gke-gke-west-2-default-pool-4cde1f72-m82p.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-9kdb5", "pod_name_emoji": "😂", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:21:55", "zone": "us-west1-a" }
Duplicación del tráfico
En esta fase, se envía tráfico al clúster de destino, pero también se refleja en el clúster canario.
La función de creación de reflejos es útil para determinar cómo afectará la carga de tráfico al rendimiento de la aplicación sin influir en las respuestas a tus clientes. Puede que no sea necesario para todos los tipos de lanzamientos, pero puede ser útil cuando se lancen cambios importantes que puedan afectar al rendimiento o a la carga.
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Sends all traffic to store-west-1 ServiceImport - backendRefs: - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 # Also mirrors all traffic to store-west-2 ServiceImport filters: - type: RequestMirror requestMirror: backendRef: group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 EOF
Con tu cliente privado, envía una solicitud a la pasarela
internal-http
. Usa la ruta/mirror
para identificar de forma única esta solicitud en los registros de la aplicación en un paso posterior.curl -H "host: store.example.internal" http://VIP/mirror
El resultado confirma que el cliente ha recibido una respuesta de un pod del clúster
gke-west-1
:{ "cluster_name": "gke-west-1", "host_header": "store.example.internal", "node_name": "gke-gke-west-1-default-pool-65059399-ssfq.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-brg5w", "pod_name_emoji": "🎖", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:24:51", "zone": "us-west1-a" }
De esta forma, se confirma que el clúster principal responde al tráfico. Aún debe confirmar que el clúster al que está migrando recibe tráfico duplicado.
Consulta los registros de aplicaciones de un pod
store
en el clústergke-west-2
. Los registros deberían confirmar que el pod ha recibido tráfico reflejado del balanceador de carga.kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
Esta salida confirma que los pods del clúster
gke-west-2
también reciben las mismas solicitudes, pero sus respuestas a estas solicitudes no se envían al cliente. Las direcciones IP que se ven en los registros son las direcciones IP internas del balanceador de carga, que se comunican con tus pods.Found 2 pods, using pod/store-5c65bdf74f-vpqbs [2023-10-12 21:05:20,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:20] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,158] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
División del tráfico
La división del tráfico es uno de los métodos más habituales para lanzar código nuevo o implementar en entornos nuevos de forma segura. El propietario del servicio define un porcentaje explícito del tráfico que se envía a los backends de la versión canary, que suele ser una cantidad muy pequeña del tráfico total, de modo que el éxito del lanzamiento se pueda determinar con un riesgo aceptable para las solicitudes de los usuarios reales.
Al dividir el tráfico con una minoría del tráfico, el propietario del servicio puede inspeccionar el estado de la aplicación y las respuestas. Si todas las señales parecen correctas, pueden continuar con el cambio completo.
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # 90% of traffic to store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 90 # 10% of traffic to store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 10 EOF
Con tu cliente privado, envía una solicitud curl continua a la
internal- http
Gateway.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
El resultado será similar a este, lo que indica que se está produciendo una división del tráfico del 90/10.
"cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-2", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", ...
Cambio de tráfico
La última fase de la migración azul-verde consiste en cambiar por completo al nuevo clúster y eliminar el antiguo. Si el propietario del servicio estuviera incorporando un segundo clúster a un clúster ya creado, este último paso sería diferente, ya que el tráfico se dirigiría a ambos clústeres. En ese caso, se recomienda un solo store
ServiceImport que tenga pods de los clústeres gke-west-1
y gke-west-2
. De esta forma, el balanceador de carga puede decidir a dónde debe dirigirse el tráfico de una aplicación activa-activa en función de la proximidad, el estado y la capacidad.
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # No traffic to the store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 0 # All traffic to the store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 100 EOF
Con tu cliente privado, envía una solicitud curl continua a la
internal- http
Gateway.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
El resultado será similar a este, lo que indica que todo el tráfico ahora se dirige a
gke-west-2
."cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", ...
Con este último paso, se completa una migración de aplicaciones azul-verde de un clúster de GKE a otro.
Desplegar el balanceo de carga basado en la capacidad
En el ejercicio de esta sección se muestran los conceptos de balanceo de carga global y capacidad de servicio desplegando una aplicación en dos clústeres de GKE de diferentes regiones. El tráfico generado se envía a varios niveles de solicitudes por segundo (RPS) para mostrar cómo se equilibra la carga del tráfico en los clústeres y las regiones.
En el siguiente diagrama se muestra la topología que vas a implementar y cómo se desborda el tráfico entre clústeres y regiones cuando el tráfico ha superado la capacidad del servicio:
Para obtener más información sobre la gestión del tráfico, consulta Gestión del tráfico de GKE.
Prepara tu entorno
Sigue los pasos que se indican en el artículo Habilitar pasarelas de varios clústeres para preparar tu entorno.
Confirma que los recursos de GatewayClass están instalados en el clúster de configuración:
kubectl get gatewayclasses --context=gke-west-1
El resultado debería ser similar al siguiente:
NAME CONTROLLER ACCEPTED AGE gke-l7-global-external-managed networking.gke.io/gateway True 16h gke-l7-global-external-managed-mc networking.gke.io/gateway True 14h gke-l7-gxlb networking.gke.io/gateway True 16h gke-l7-gxlb-mc networking.gke.io/gateway True 14h gke-l7-regional-external-managed networking.gke.io/gateway True 16h gke-l7-regional-external-managed-mc networking.gke.io/gateway True 14h gke-l7-rilb networking.gke.io/gateway True 16h gke-l7-rilb-mc networking.gke.io/gateway True 14h
Desplegar una aplicación
Despliega el servidor de la aplicación web de ejemplo en ambos clústeres:
kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
El resultado debería ser similar al siguiente:
namespace/store created
deployment.apps/store created
Desplegar un servicio, una pasarela y una ruta HTTP
Aplica el siguiente manifiesto
Service
a los clústeresgke-west-1
ygke-east-1
:cat << EOF | kubectl apply --context gke-west-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: traffic-test annotations: networking.gke.io/max-rate-per-endpoint: "10" spec: ports: - port: 8080 targetPort: 8080 name: http selector: app: store type: ClusterIP --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: traffic-test EOF
cat << EOF | kubectl apply --context gke-east-1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: traffic-test annotations: networking.gke.io/max-rate-per-endpoint: "10" spec: ports: - port: 8080 targetPort: 8080 name: http selector: app: store type: ClusterIP --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: traffic-test EOF
El servicio se anota con
max-rate-per-endpoint
definido en 10 solicitudes por segundo. Con 2 réplicas por clúster, cada servicio tiene una capacidad de 20 RPS por clúster.Para obtener más información sobre cómo elegir un nivel de capacidad de servicio, consulta Determinar la capacidad de un servicio.
Aplica el siguiente manifiesto
Gateway
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store namespace: traffic-test spec: gatewayClassName: gke-l7-global-external-managed-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOF
El manifiesto describe una pasarela externa, global y multiclúster que implementa un balanceador de carga de aplicación externo con una dirección IP accesible públicamente.
Aplica el siguiente manifiesto
HTTPRoute
al clúster de configuración,gke-west-1
en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store namespace: traffic-test labels: gateway: store spec: parentRefs: - kind: Gateway namespace: traffic-test name: store rules: - backendRefs: - name: store group: net.gke.io kind: ServiceImport port: 8080 EOF
El manifiesto describe un HTTPRoute que configura la Gateway con una regla de enrutamiento que dirige todo el tráfico al ServiceImport de la tienda. El
store
ServiceImport agrupa losstore
pods de servicio de ambos clústeres y permite que el balanceador de carga los trate como un único servicio.Puedes consultar los eventos de la pasarela al cabo de unos minutos para ver si se ha terminado de implementar:
kubectl describe gateway store -n traffic-test --context gke-west-1
El resultado debería ser similar al siguiente:
... Status: Addresses: Type: IPAddress Value: 34.102.159.147 Conditions: Last Transition Time: 2023-10-12T21:40:59Z 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-12T21:40:59Z Message: Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2023-10-12T21:40:59Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T21:40:59Z 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-12T21:40:59Z Message: Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Last Transition Time: 2023-10-12T21:40:59Z 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 ADD 12m mc-gateway-controller traffic-test/store Normal SYNC 6m43s mc-gateway-controller traffic-test/store Normal UPDATE 5m40s (x4 over 12m) mc-gateway-controller traffic-test/store Normal SYNC 118s (x6 over 10m) mc-gateway-controller SYNC on traffic-test/store was a success
Este resultado muestra que la pasarela se ha desplegado correctamente. Puede que el tráfico tarde unos minutos en empezar a pasar después de que se haya implementado la pasarela. Anota la dirección IP de este resultado, ya que se usará en un paso posterior.
Confirmar el tráfico
Confirma que el tráfico se está enviando a la aplicación probando la dirección IP de la pasarela con un comando curl:
curl GATEWAY_IP_ADDRESS
El resultado debería ser similar al siguiente:
{
"cluster_name": "gke-west-1",
"host_header": "34.117.182.69",
"pod_name": "store-54785664b5-mxstv",
"pod_name_emoji": "👳🏿",
"project_id": "project",
"timestamp": "2021-11-01T14:06:38",
"zone": "us-west1-a"
}
En este resultado se muestran los metadatos del pod, que indican la región desde la que se ha atendido la solicitud.
Verificar el tráfico mediante pruebas de carga
Para verificar que el balanceador de carga funciona, puedes desplegar un generador de tráfico en tu clúster gke-west-1
. El generador de tráfico genera tráfico en diferentes niveles de carga para demostrar la capacidad y las funciones de desbordamiento del balanceador de carga. En los siguientes pasos se muestran tres niveles de carga:
- 10 RPS, que es inferior a la capacidad del servicio de la tienda en
gke-west-1
. - 30 RPS, que supera la capacidad del servicio de tienda
gke-west-1
y provoca un desbordamiento del tráfico agke-east-1
. - 60 RPS, que supera la capacidad de los servicios de ambos clústeres.
Configurar el panel de control
Obtén el nombre del mapa de URLs subyacente de tu Gateway:
kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
El resultado debería ser similar al siguiente:
/projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
En la Google Cloud consola, ve a la página Explorador de métricas.
En Seleccionar una métrica, haga clic en CÓDIGO: MQL.
Introduce la siguiente consulta para observar las métricas de tráfico del servicio de la tienda en tus dos clústeres:
fetch https_lb_rule | metric 'loadbalancing.googleapis.com/https/backend_request_count' | filter (resource.url_map_name == 'GATEWAY_URL_MAP') | align rate(1m) | every 1m | group_by [resource.backend_scope], [value_backend_request_count_aggregate: aggregate(value.backend_request_count)]
Sustituye
GATEWAY_URL_MAP
por el nombre de la asignación de URLs del paso anterior.Haz clic en Realizar una consulta. Espera al menos 5 minutos después de implementar el generador de carga de la siguiente sección para que las métricas se muestren en el gráfico.
Prueba con 10 RPS
Despliega un pod en tu clúster
gke-west-1
:kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 10'
Sustituye
GATEWAY_IP_ADDRESS
por la dirección IP de la puerta de enlace del paso anterior.La salida es similar a la siguiente, lo que indica que el generador de tráfico está enviando tráfico:
If you don't see a command prompt, try pressing enter.
El generador de carga envía continuamente 10 RPS a la puerta de enlace. Aunque el tráfico proceda de una región de Google Cloud , el balanceador de carga lo trata como tráfico de cliente procedente de la costa oeste de EE. UU. Para simular una diversidad de clientes realista, el generador de carga envía cada solicitud HTTP como una nueva conexión TCP, lo que significa que el tráfico se distribuye de forma más uniforme entre los pods de backend.
El generador tarda hasta 5 minutos en generar tráfico para el panel de control.
Consulta tu panel de control Explorador de métricas. Aparecen dos líneas que indican la cantidad de tráfico que se balancea de carga en cada uno de los clústeres:
Deberías ver que
us-west1-a
recibe aproximadamente 10 RPS de tráfico, mientras queus-east1-b
no recibe tráfico. Como el generador de tráfico se ejecuta enus-west1
, todo el tráfico se envía al servicio del clústergke-west-1
.Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:
kubectl delete pod loadgen --context gke-west-1
Prueba con 30 RPS
Vuelve a implementar el generador de carga, pero configurado para enviar 30 RPS:
kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 30'
El generador tarda hasta 5 minutos en generar tráfico para el panel de control.
Consulta tu panel de control de Cloud Ops.
Deberías ver que se envían aproximadamente 20 RPS a
us-west1-a
y 10 RPS aus-east1-b
. Esto indica que el servicio degke-west-1
está totalmente utilizado y que se está transfiriendo un exceso de 10 RPS de tráfico al servicio degke-east-1
.Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:
kubectl delete pod loadgen --context gke-west-1
Prueba con 60 RPS
Implementa el generador de carga configurado para enviar 60 RPS:
kubectl run --context gke-west-1 -i --tty --rm loadgen \ --image=cyrilbkr/httperf \ --restart=Never \ -- /bin/sh -c 'httperf \ --server=GATEWAY_IP_ADDRESS \ --hog --uri="/zone" --port 80 --wsess=100000,1,1 --rate 60'
Espera 5 minutos y consulta tu panel de control de Cloud Ops. Ahora debería mostrar que ambos clústeres reciben aproximadamente 30 RPS. Como todos los servicios están sobreutilizados a nivel mundial, no hay desbordamiento de tráfico y los servicios absorben todo el tráfico que pueden.
Detén el generador de carga con Ctrl+C y, a continuación, elimina el pod:
kubectl delete pod loadgen --context gke-west-1
Limpieza
Después de completar los ejercicios de esta página, sigue estos pasos para quitar recursos y evitar que se apliquen cargos no deseados a tu 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 disable
Inhabilitar entrada de varios clústeres:
gcloud container fleet ingress disable
Inhabilita las APIs:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
Usar la puerta de enlace de varios clústeres con VPC compartida
También se puede implementar una pasarela de varios clústeres en un entorno de VPC compartida con diferentes topologías, según el caso práctico.
En la siguiente tabla se describen las topologías de Gateway multiclúster admitidas en un entorno de VPC compartida:
Situación | Proyecto del host de la flota | Configurar clúster | Clústeres de cargas de trabajo |
---|---|---|---|
1 | Proyecto de host de VPC compartida | Proyecto de host de VPC compartida | Proyecto de host de VPC compartida |
2 | Proyecto de servicio de VPC compartida | Proyecto de servicio de VPC compartida (igual que el proyecto de servicio de flota) |
Proyecto de servicio de VPC compartida (igual que el proyecto de servicio de flota) |
Para crear gateways de varios clústeres en un entorno de VPC compartida, sigue estos pasos:
Sigue los pasos para configurar servicios de varios clústeres con VPC compartida.
Crea tus servicios y expórtalos al clúster de configuración
Si tienes previsto usar una pasarela interna de varios clústeres, crea una subred de solo proxy.
Crea tu Gateway externo o interno y tus HTTPRoutes multiclúster
Una vez que hayas completado estos pasos, podrás validar tu implementación en función de tu topología.
Solución de problemas
No existe una subred de solo proxy para la pasarela interna
Si aparece el siguiente evento en tu pasarela interna, significa que no existe una subred solo de proxy para esa región. Para solucionar este problema, implementa una subred solo de proxy.
generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.
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
.
Siguientes pasos
- Consulta más información sobre el controlador de la pasarela.