En esta página, se describe cómo implementar recursos de Gateway de Kubernetes para el balanceo de cargas en varios clústeres de Google Kubernetes Engine (GKE). Antes de implementar Gateways de varios clústeres, consulta Habilita las Gateways de varios clústeres para preparar tu entorno. Para implementar Gateways en un solo clúster de GKE, consulta Implementa Gateways.
Gateways de varios clústeres
Una Gateway de varios clústeres es un recurso de Gateway que balancea las cargas del tráfico en varios clústeres de Kubernetes. En GKE, las GatewayClasses gke-l7-gxlb-mc
, gke-l7-global-external-managed-mc
y gke-l7-rilb-mc
implementan Gateways de varios clústeres que proporcionan enrutamiento HTTP, división de tráfico, duplicación de 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 en diferentes regiones. Con las Gateways de varios clústeres, la administración de herramientas de redes de aplicaciones en varios clústeres y equipos es fácil, segura y escalable para los administradores de infraestructura.
En esta página, se presentan tres ejemplos para enseñarte a implementar Gateways de varios clústeres con el controlador de Gateway de GKE:
- Ejemplo 1: Una Gateway externa de varios clústeres que proporciona balanceo de cargas en dos clústeres de GKE para el tráfico de Internet.
- Ejemplo 2: División del tráfico azul-verde basada en peso y duplicación de tráfico en dos clústeres de GKE para el tráfico de VPC interno.
En cada uno de los ejemplos, se usarán las mismas aplicaciones de tienda y sitio para modelar una situación real en la que un servicio de compras en línea y un servicio de sitio web son controlados y administrados por equipos diferentes, y están implementados en una flota de clústeres de GKE compartidos. En cada uno de los ejemplos, se destacan diferentes topologías y casos de uso habilitados por Gateways de varios clústeres.
Las Gateways de varios clústeres requieren cierta preparación del entorno antes de que puedan implementarse. Antes de continuar, sigue los pasos en Habilita Gateways de varios clústeres:
Implemente clústeres de GKE
Registra tus clústeres en una flota.
Habilita el Servicie de varios clústeres y los controladores de Gateways de varios clústeres.
Por último, revisa el controlador de Gateway de GKE Vista previa de las limitaciones y problemas conocidos antes de usarlo en tu entorno.
Gateway externa, varios clústeres y varias regiones
En este instructivo, crearás una Gateway externa de varios clústeres que entrega tráfico externo en una aplicación que se ejecuta en dos clústeres de GKE.
En los siguientes pasos, haz lo siguiente:
- Implementa la aplicación
store
de muestra en los clústeresgke-west-1
ygke-east-1
. - Configura recursos de ServiceExport en cada clúster para exportar los Services a tu flota.
- Implementa una Gateway
gke-l7-gxlb-mc
y una HTTPRoute en el clúster de configuración,gke-west-1
. Podrías usar una Gatewaygke-l7-global-external-managed
como alternativa para aprovechar todas las capacidades avanzadas de administración de tráfico del balanceador de cargas de HTTP(S) externo global.
Después de implementar la aplicación y los recursos de Gateway, puedes controlar el tráfico en los dos clústeres de GKE con el enrutamiento basado en rutas de acceso:
- Las solicitudes a
/west
se enrutan a los Podsstore
en el clústergke-west-1
. - Las solicitudes a
/east
se enrutan a los Podsstore
en el clústergke-east-1
. - Las solicitudes a cualquier otra ruta de acceso se enrutan a cualquiera de los clústeres, según su estado, capacidad y proximidad al cliente solicitante.
Implementa la aplicación de demostración
Crea la implementación
store
y el espacio de nombres en los tres clústeres que se implementaron en Habilita Gateways 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
Implementa 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 app implementada en este paso. Asegúrate de que la app se implemente 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
, ygke-west-2
se usa en otro ejemplo.
Service de varios clústeres
Los servicios son la forma en que los Pods se exponen a los clientes. Debido a que el controlador de Gateway de GKE usa el balanceo de cargas nativo del contenedor, no usa el balanceo de cargas de ClusterIP o Kubernetes para llegar a los Pods. El tráfico se envía directamente desde el balanceador de cargas a las IP del Pod. Sin embargo, los objetos Service desempeñan una función crítica como un identificador lógico para la agrupación de Pods.
Los servicios de varios clústeres (MCS) son un estándar de API para los Services que abarcan clústeres y un controlador de GKE que proporciona descubrimiento de servicios en clústeres de GKE. El controlador de la Gateway de varios clústeres usa recursos de la API de MCS para agrupar Pods en un Service que se pueda dirigir a varios profesionales o a través de ellos.
La API de Services de varios clústeres define los siguientes recursos personalizados:
- ServiceExports asigna a un Service de Kubernetes mediante la exportación de los extremos de ese Service a todos los clústeres registrados en la flota. Cuando un Service tiene una ServiceExport correspondiente, significa que se puede abordar con una Gateway de varios clústeres.
- El controlador de Service de varios clústeres genera ServiceImports de forma automática. ServiceExport y ServiceImports vienen en pares. Si existe una ServiceExport en la flota, se crea una ServiceImport correspondiente para permitir que se acceda al Service asignado a ServiceExport desde todos los clústeres.
La exportación de Services funciona de la siguiente manera. Existe un Service de almacenamiento en gke-1
que selecciona un grupo de Pods en ese clúster. Se crea una ServiceExport en el clúster que permite que se pueda acceder a los Pods en gke-1
desde los otros clústeres de la flota. ServiceExport se asignará a los Services que tengan el mismo nombre y el mismo espacio de nombres que el recurso de ServiceExport y los expondrá.
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 sucede después de implementar una ServiceExport. Si existe un par Service y ServiceExport, el controlador de Service de varios clústeres implementa una ServiceImport correspondiente en cada clúster de GKE de la flota. ServiceImport es la representación local del Service store
en cada clúster. Esto permite que el Pod de cliente en gke-2
use ClusterIP o los Service sin interfaz gráfica para llegar a los Pods store
en gke-1
. Cuando se usan de esta manera, los Service de varios clústeres proporcionan un balanceo de cargas este-oeste entre clústeres. Si deseas usar los Service de varios clústeres para el balanceo de cargas de clúster a clúster, consulta Configura Service de varios clústeres.
Las Gateway de varios clústeres también usan ServiceImports, pero no para el balanceo de cargas de clúster a clúster. En cambio, las Gateway usan ServiceImports como identificadores lógicos para un Service que existe en otro clúster o que se extiende a varios clústeres. La siguiente HTTPRoute hace referencia a una ServiceImport en lugar de un recurso de Service. Si se hace referencia a una ServiceImport, esto indica que reenvía el tráfico a un grupo de Pods de backend que se ejecutan en uno o más 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:
- name: store
port: 8080
En el siguiente diagrama, se muestra cómo la HTTPRoute enruta el tráfico store.example.com
a los Pods store
en gke-1
y gke-2
. El balanceador de cargas los trata como un grupo de backends. Si los Pods de uno de los clústeres se encuentran en mal estado, son inaccesibles o no tienen capacidad de tráfico, la carga de tráfico se balancea a los Pods restantes en el otro clúster. Los clústeres nuevos se pueden agregar o quitar con el Service store
y ServiceExport. Esto agregará o quitará con transparencia los Pods de backend sin ningún cambio explícito en la configuración del enrutamiento.
Exporta Services
En este punto, la aplicación se ejecuta en ambos clústeres. A continuación, deberás exponer las aplicaciones y exportarlas mediante la implementación de objetos Service y ServiceExports en cada clúster.
Guarda el siguiente manifiesto como un archivo llamado
store-west-service.yaml
: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
Implementa este manifiesto en
gke-west-1
:kubectl apply -f store-west-service.yaml --context gke-west-1
Guarda el siguiente manifiesto como un archivo llamado
store-east-service.yaml
: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
Implementa este recurso
ServiceExport
engke-east-1
:kubectl apply -f store-east-service.yaml --context gke-east-1 --namespace store
Verifica que se hayan creado las ServiceExports correctas en el clúster.
kubectl get serviceexports --context CLUSTER_NAME --namespace store
Reemplaza CLUSTER_NAME por
gke-west-1
ygke-east-1
. El resultado debe parecerse al 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 Service
store
contiene Podsstore
en ambos clústeres, mientras que los Servicestore-west-1
ystore-east-1
solo contienen Podsstore
en sus clústeres respectivos. Estos Service superpuestos se usan para apuntar a los Pods en varios clústeres o en un subconjunto de Pods en un solo clúster.Después de unos minutos, verifica que el controlador de Services de varios clústeres haya creado de forma automática el
ServiceImports
adjunto 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
. El resultado debe parecerse al 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 Services desde ambos clústeres en la flota. Sin embargo, debido a que solo hay un clúster de configuración activo por flota, solo puedes implementar Gateways y HTTPRouters que hagan referencia a estas ServiceImports en gke-west-1
. Cuando una HTTPRouter en el clúster de configuración hace referencia a estas ServiceImports como backends, la Gateway puede reenviar tráfico a estos servicios sin importar desde qué clúster se exporten.
Implementa Gateway y HTTPRoute
Una vez que se implementaron las aplicaciones, puedes configurar una Gateway con la GatewayClass gke-l7-gxlb-mc
. Esta Gateway crea un balanceador de cargas de HTTP(S) externo configurado para distribuir el tráfico entre los clústeres de destino.
Guarda el siguiente manifiesto
Gateway
como un archivo llamadoexternal-http-gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: external-http namespace: store spec: gatewayClassName: gke-l7-gxlb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute
Esto usa
gke-l7-gxlb-mc
GatewayClassAplica el manifiesto de Gateway al clúster de configuración
gke-west-1
de este ejemplo:kubectl apply -f external-http-gateway.yaml --context gke-west-1 --namespace store
Guarda el siguiente manifiesto de HTTPRoute en un archivo llamado
public-store-route.yaml
: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
Una vez implementada, esta HTTPRoute configurará el siguiente comportamiento de enrutamiento:
- Las solicitudes a
/west
se enrutan a los Podsstore
en el clústergke-west-1
. - Las solicitudes a
/east
se enrutan a los Podsstore
en el clústergke-east-1
. - Las solicitudes a cualquier otra ruta de acceso se enrutan a cualquiera de los clústeres, según su estado, capacidad y proximidad al cliente solicitante.
Ten en cuenta que si todos los Pods en un clúster determinado están en mal estado (o no existen), el tráfico al Service store
solo se enviará a los clústeres que en realidad tengan Pods store
. La existencia de una ServiceExport y un Service en un clúster determinado no garantiza que el tráfico se envíe a ese clúster. Los Pods deben existir y responder de manera afirmativa a la verificación de estado del balanceador de cargas. De lo contrario, el balanceador de cargas solo enviará tráfico a Pods store
en buen estado en otros clústeres.
Aplica el manifiesto de
HTTPRoute
al clúster de configuracióngke-1
de este ejemplo:kubectl apply -f public-store-route.yaml --context gke-west-1 --namespace store
En el siguiente diagrama, se muestran los recursos que implementaste en ambos clústeres.
Debido a que gke-west-1
es el clúster de configuración de Gateway, es el clúster en el que el controlador de Gateway observa nuestras Gateway, HTTPRoutes y ServiceImports. Cada clúster tiene una ServiceImport store
y otra ServiceImport específica para ese clúster. Ambos apuntan a los mismos Pods. Esto permite que HTTPRoute especifique con exactitud dónde debe ir el tráfico: a los Pods store
en un clúster específico o a los Pods store
en todos los clústeres.
Ten en cuenta que este es un modelo de recursos lógico, no una descripción del flujo de tráfico. La ruta de tráfico va directamente del balanceador de cargas a los Pods de backend y no tiene relación directa con el clúster que es el clúster de configuración.
Valida la implementación
Ahora puedes emitir solicitudes a nuestra Gateway de varios clústeres y distribuir el tráfico entre varios clústeres de GKE.
Verifica que el objeto Gateway y HTTPRoute se hayan implementado de forma correcta inspeccionando del estado y los eventos de Gateway.
kubectl describe gateways.gateway.networking.k8s.io external-http --context gke-west-1 --namespace store
El resultado debería ser similar al siguiente:
Spec: Gateway Class Name: gke-l7-gxlb-mc Listeners: Port: 80 Protocol: HTTP Routes: Group: networking.k8s.io Kind: HTTPRoute Namespaces: From: Same Selector: Match Labels: Gateway: external-http Status: Addresses: Type: IPAddress Value: 34.120.172.213 Conditions: Last Transition Time: 1970-01-01T00:00:00Z Message: Waiting for controller Reason: NotReconciled Status: False Type: Scheduled Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal UPDATE 29m (x2 over 29m) global-gke-gateway-ctlr store/external-http Normal SYNC 59s (x9 over 29m) global-gke-gateway-ctlr SYNC on store/external-http was a success
Una vez que la Gateway se implementó correctamente, recupera la dirección IP externa de la Gateway
external-http
.kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
Reemplaza
VIP
en los siguientes pasos por la dirección IP que recibas como resultado.Envía tráfico a la ruta raíz del dominio. Esto balancea las cargas del tráfico a la ServiceImport
store
, que se encuentra en los clústeresgke-west-1
ygke-east-1
. El balanceador de cargas envía tu tráfico a la región más cercana a ti y es posible que no veas respuestas de la otra región.curl -H "host: store.example.com" http://VIP
El resultado confirma que el Pod entregó la solicitud desde el clúster
gke-west-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 el tráfico a la ruta
/west
. Esto enruta el tráfico a la ServiceImportstore-west
, que solo tiene Pods en ejecución en el clústergke-west-1
. Un objeto ServiceImport específico del clúster, comostore-west
, permite que el propietario de una aplicación envíe tráfico de forma explícita a un clúster específico, en lugar de permitir que el balanceador de cargas tome la decisión.curl -H "host: store.example.com" http://VIP/west
El resultado confirma que el Pod entregó la solicitud desde el 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 el Pod entregó la solicitud desde el 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" }
Enrutamiento azul-verde y de varios clústeres con Gateway
Las GatewayClasses gke-l7-rilb-*
y gke-l7-global-external-managed-*
tienen muchas capacidades avanzadas de enrutamiento de tráfico, que incluyen la división del tráfico, la coincidencia del encabezado, la manipulación del encabezado, la duplicación de tráfico y mucho más. En este ejemplo, demostrarás cómo usar la división de tráfico basada en la ponderación para controlar de forma explícita la proporción de tráfico en dos clústeres de GKE.
En este ejemplo, se explican algunos pasos realistas que seguiría un propietario del servicio para trasladar o expandir su aplicación a un clúster de GKE nuevo. El objetivo de las implementaciones azul-verde es reducir el riesgo mediante varios pasos de validación que confirman que el clúster nuevo funciona de forma correcta. En este ejemplo, se explican cuatro etapas de implementación:
- 100%-versión canary basada en encabezados: Usa el enrutamiento de encabezado HTTP para enviar solo tráfico sintético o de prueba al clúster nuevo.
- 100%-duplicación del tráfico: Duplica el tráfico de usuario al clúster de versión canary. Esto prueba la capacidad del clúster de versión canary mediante la copia del 100% del tráfico de usuario en este clúster.
- 90%-10%: Versión canary de una división del tráfico del 10% para exponer lentamente el clúster nuevo al tráfico en vivo.
- 0%-100%: Adopta una migración de sistemas completa al clúster nuevo con la opción de volver a la anterior si se observan errores.
Este ejemplo es similar al anterior, excepto que implementa una Gateway de varios clústeres interna en su lugar. De esta manera, se implementa un balanceador de cargas HTTP(S) interno al que solo se puede acceder de forma privada desde la VPC. Usarás los clústeres y la misma aplicación que implementaste en los pasos anteriores, con la excepción de que los implementarás a través de una Gateway diferente.
Requisitos previos
El siguiente ejemplo se basa en algunos de los pasos de Implementa una Gateway de varios clústeres externa. Antes de continuar con este ejemplo, asegúrate de haber realizado los siguientes pasos:
En este ejemplo, se usan los clústeres gke-west-1
y gke-west-2
que ya configuraste. Estos clústeres están en la misma región porque GatewayClass gke-l7-rilb-mc
es regional y solo admite backends de clúster en la misma región.
Implementa el Service y las ServiceExports necesarios en cada clúster. Si implementaste Services y ServiceExports del ejemplo anterior, ya implementaste 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
Implementa un conjunto similar de recursos 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
Configura una subred de solo proxy
Si aún no lo has hecho, configura una subred de solo proxy para cada región en la que implementes puertas de enlace einternas. Esta subred se usa para proporcionar direcciones IP internas a los proxies de balanceador de cargas.
Debes crear una subred de solo proxy antes de crear Gateways que administren los balanceadores de cargas HTTP(S) internos. Cada región de una red privada virtual (VPC) en la que uses balanceadores de cargas HTTP(S) internos debe tener una subred de solo proxy.
Con el comando gcloud compute networks subnets create
, se 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
Reemplaza lo siguiente:
SUBNET_NAME
: El nombre de la subred de solo proxyREGION
: La región de la subred de solo proxyVPC_NETWORK_NAME
: El nombre de la red de VPC que contiene la subredCIDR_RANGE
: El rango de direcciones IP principal de la subred Debes usar una máscara de subred de un tamaño máximo de/26
a fin de que al menos 64 direcciones IP estén disponibles para los proxies de la región. La máscara de subred recomendada es/23
.
Si el siguiente evento aparece en tu Gateway interna, no existe una subred de solo proxy para esa región. Para resolver este problema, implementa una subred de solo 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.
Implementa la Gateway
La siguiente Gateway se crea a partir de la puerta de enlace gke-l7-rilb-mc
. Esta es una Gateway regional que solo puede apuntar a clústeres de GKE en la misma región.
Si aún no lo has hecho, crea una subred de solo proxy para el balanceador de cargas interno. Esto es necesario para que el balanceador de cargas interno funcione correctamente, ya que crea una subred que se usa para proporcionar direccionamiento IP a los proxies de balanceador de cargas. Crea la subred de solo proxy en la misma región en la que se encuentra tu clúster.
Guarda el siguiente manifiesto de Gateway en un archivo llamado
internal-http-gateway.yaml
: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
Aplica el manifiesto de Gateway al clúster de configuración
gke-west-1
de este ejemplo:kubectl apply -f internal-http-gateway.yaml --context gke-west-1 --namespace store
Verifica que la Gateway haya aparecido correctamente. Puedes filtrar solo los eventos de esta Gateway con el siguiente comando:
kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
La implementación de Gateway se realizó de forma correcta si el resultado es similar al siguiente:
LAST SEEN TYPE REASON OBJECT MESSAGE 22m Normal ADD gateway/internal-http store/internal-http 6m50s Normal UPDATE gateway/internal-http store/internal-http 11m Normal SYNC gateway/internal-http store/internal-http 3m26s Normal SYNC gateway/internal-http SYNC on store/internal-http was a success
Versión canary basada en encabezados
La versión canary basada en encabezados permite que el propietario del servicio haga coincidir el tráfico de prueba sintético que no proviene de usuarios reales. Esta es una forma fácil de validar que la red básica de la aplicación está funcionando sin exponer a los usuarios directamente.
Guarda el siguiente manifiesto YAML como un archivo llamado
internal-route-stage-1.yaml
.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
Una vez implementado, este HTTPRoute configura el siguiente comportamiento de enrutamiento:
- Las solicitudes internas a
store.example.internal
sin el encabezado HTTPenv: canary
se enrutan a los Podsstore
en el clústergke-west-1
. - Las solicitudes internas a
store.example.internal
con el encabezado HTTPenv: canary
se enrutan a los Podsstore
en el clústergke-west-2
.
Aplica
internal-route-stage-1.yaml
al clústergke-west-1
:kubectl apply -f internal-route-stage-1.yaml --context gke-west-1 --namespace store
Envía tráfico a la dirección IP de la Gateway para validar que la HTTPRoute funcione correctamente.
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
Reemplaza VIP en los siguientes pasos por la dirección IP que recibas como resultado.
Envía una solicitud a la Gateway con el encabezado HTTP
env: canary
. Esto confirmará que el tráfico se enruta agke-west-2
. Usa un cliente privado en la misma VPC que los clústeres de GKE para confirmar que las solicitudes se enrutan de forma correcta. El siguiente comando debe ejecutarse en una máquina que tenga acceso privado a la dirección IP de Gateway o no funcionará.curl -H "host: store.example.internal" -H "env: canary" http://VIP
El resultado confirma que un Pod entregó la solicitud desde el 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 de tráfico
En esta etapa, se envía el tráfico al clúster deseado, pero también se duplica ese tráfico en el clúster de versión canary.
Guarda el siguiente manifiesto YAML como un archivo llamado
internal-route-stage-2.yaml
.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
Aplica
internal-route-stage-2.yaml
al clústergke-west-1
:kubectl apply -f internal-route-stage-2.yaml --context gke-west-1 --namespace store
Con tu cliente privado, envía una solicitud a la Gateway
internal-http
. Usa la ruta de acceso/mirror
para poder 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 recibió una respuesta de un Pod en el 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" }
Esto confirma que el clúster principal responde al tráfico. Aún debes confirmar que el clúster al que migras reciba tráfico duplicado.
Verifica los registros de la aplicación de un Pod
store
en el clústergke-west-2
. Los registros deben confirmar que el Pod recibió tráfico duplicado del balanceador de cargas.kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
Este resultado confirma que los Pods en el clúster
gke-west-2
también reciben las mismas solicitudes. Sin embargo, sus respuestas a estas solicitudes no se envían al cliente. Las direcciones IP que se ven en los registros son las de las direcciones IP internas del balanceador de cargas que se comunican con los Pods.Found 2 pods, using pod/store-5f5b954888-gtldf 2021-05-31 01:32:21,416 ... "GET /mirror HTTP/1.1" 200 - 2021-05-31 01:32:23,323 ... "GET /mirror HTTP/1.1" 200 - 2021-05-31 01:32:24,137 ... "GET /mirror HTTP/1.1" 200 -
El uso de la duplicación es útil para determinar cómo la carga de tráfico afectará el rendimiento de la aplicación sin afectar de ninguna manera las respuestas a los clientes. Puede no ser necesario para todos los tipos de implementaciones, pero puede ser útil cuando se implementan cambios grandes que podrían afectar el rendimiento o la carga.
División del tráfico
La división del tráfico es uno de los métodos más comunes para implementar código nuevo o implementar en entornos nuevos de forma segura. El propietario del servicio establece un porcentaje explícito de tráfico que se envía a los backends de versión canary, que suele ser una cantidad muy pequeña del tráfico general para que el éxito de la implementación se pueda determinar con una cantidad aceptable de riesgos para las solicitudes de usuarios reales.
Guarda el siguiente manifiesto YAML como un archivo llamado
internal-route-stage-3.yaml
.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
Aplica
internal-route-stage-3.yaml
al clústergke-west-1
:kubectl apply -f internal-route-stage-3.yaml --context gke-west-1 --namespace store
Con tu cliente privado, envía una solicitud curl continua a la Gateway
internal- http
.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á realizando una división del tráfico de 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", ...
Si se hace una división del 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 todos los indicadores se ven en buen estado, puede continuar con la migración de sistemas completa.
Migración de tráfico
La última etapa de la migración azul-verde es migrar por completo al clúster nuevo y quitar el clúster anterior. Si el propietario del servicio estuviera integrando un segundo clúster a un clúster existente, este último paso sería diferente, ya que el último paso tendría tráfico hacia ambos clústeres. En ese caso, se recomienda una sola ServiceImport store
que tenga Pods de los clústeres gke-west-1
y gke-west-2
. Esto permite que el balanceador de cargas tome la decisión de dónde debe dirigirse el tráfico para una aplicación activa-activa, según la proximidad, el estado y la capacidad.
Guarda el siguiente manifiesto YAML como un archivo llamado
internal-route-stage-4.yaml
.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
Aplica
internal-route-stage-4.yaml
al clústergke-west-1
:kubectl apply -f internal-route-stage-4.yaml --context gke-west-1 --namespace store
Con tu cliente privado, envía una solicitud curl continua a la Gateway
internal- http
.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 se dirige ahora a
gke-west-2
."cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", ...
En este último paso, se completa una migración de aplicación azul-verde de un clúster de GKE a otro.
Implementa el balanceo de cargas basado en la capacidad
En el ejercicio de esta sección, se muestran los conceptos del balanceo de cargas global y la capacidad del Service mediante la implementación de una aplicación en dos clústeres de GKE en diferentes regiones. El tráfico generado se envía en varios niveles de solicitudes por segundo (RPS) para mostrar cómo se balancean las cargas del tráfico entre los clústeres y las regiones.
En el siguiente diagrama, se muestra la topología que implementarás y cómo el tráfico se desborda entre clústeres y regiones cuando el tráfico supera la capacidad del Service:
Para obtener más información sobre la administración del tráfico, consulta Administración del tráfico de GKE.
Prepara el entorno
Sigue Habilita Gateways 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 es similar a este:
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 16h gke-l7-gxlb networking.gke.io/gateway True 16h gke-l7-gxlb-mc networking.gke.io/gateway True 16h gke-l7-rilb networking.gke.io/gateway True 16h gke-l7-rilb-mc networking.gke.io/gateway True 16h
Implementa una aplicación
Implementa el servidor de aplicaciones web de muestra 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 es similar a este:
namespace/store created
deployment.apps/store created
Implementa un Service, una Gateway y una HTTPRoute
Guarda el siguiente manifiesto de muestra como
store-service.yaml
: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
En este manifiesto, se describe un Service y un objeto ServiceExport que exporta el Service en clústeres como un Service de varios clústeres. El objeto ServiceExport indica que los extremos del Service de almacenamiento en este clúster se agregan con los extremos de todos los demás Services de almacenamiento dentro de la flota. ServiceExport actúa como la marca de habilitación para convertir un Service en un Service de varios clústeres. El valor de
max-rate-per-endpoint
es10
. Con 2 réplicas, cada Service tiene 20 RPS de capacidad por clúster.A fin de obtener más información sobre cómo elegir un nivel de capacidad de servicio para tu Service, consulta Determina la capacidad de tu Service.
Aplica el manifiesto a ambos clústeres:
kubectl apply -f store-service.yaml --context gke-west-1 kubectl apply -f store-service.yaml --context gke-east-1
Guarda el siguiente manifiesto de muestra como
store-gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: store namespace: traffic-test spec: gatewayClassName: gke-l7-gxlb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute
En el manifiesto, se describe una Gateway externa, global y de varios clústeres que implementa un balanceador de cargas HTTP(S) externo con una dirección IP de acceso público.
Aplica el manifiesto a tu clúster de configuración:
kubectl apply -f store-gateway.yaml --context gke-west-1
Guarda el siguiente manifiesto de muestra como
store-route.yaml
: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
El manifiesto describe una HTTPRoute que configura la Gateway con una regla de enrutamiento que dirige todo el tráfico al ServiceImport de almacenamiento. El objeto ServiceImport de almacenamiento agrupa los Pods del Service de almacenamiento en ambos clústeres y permite que los balanceadores de cargas se dirijan a ellos como un solo Service.
Aplica el manifiesto a tu clúster de configuración:
kubectl apply -f store-route.yaml --context gke-west-1
La Gateway puede tardar varios minutos en implementarse completamente. Puedes verificar los eventos de la Gateway después de unos minutos para ver si finalizó la implementación:
kubectl describe gateways.gateway.networking.k8s.io store -n traffic-test
El resultado es similar a este:
... Status: Addresses: Type: IPAddress Value: 34.117.182.69 Conditions: Last Transition Time: 1970-01-01T00:00:00Z Message: Waiting for controller Reason: NotReconciled Status: False Type: Scheduled Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ADD 8m13s mc-gateway-controller traffic-test/store Normal SYNC 7m57s mc-gateway-controller traffic-test/store Warning SYNC 6m14s mc-gateway-controller failed to translate Gateway "traffic-test/store": no GroupKey's for port 8080 exist Normal UPDATE 2m6s (x3 over 8m13s) mc-gateway-controller traffic-test/store Normal SYNC 2m6s mc-gateway-controller SYNC on traffic-test/store was a success
En este resultado, se muestra que la Gateway se implementó de forma correcta. Es posible que el tráfico tarde unos minutos en comenzar a pasar después de que se implemente la Gateway. Toma nota de la dirección IP en este resultado, ya que se usa en el siguiente paso.
Confirma el tráfico
Para confirmar que el tráfico pase a la aplicación, prueba la dirección IP de la Gateway con un comando curl:
curl GATEWAY_IP_ADDRESS
El resultado es similar a este:
{
"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 entregó la solicitud.
Verifica el tráfico mediante pruebas de carga
Para verificar que el balanceador de cargas funcione, puedes implementar 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 cargas. En los siguientes pasos, se demuestran tres niveles de carga:
- 10 RPS, que está por debajo de la capacidad del Service de almacenamiento en
gke-west-1
. - 30 RPS, que está por sobre la capacidad para el Service de almacenamiento
gke-west-1
y provoca un desbordamiento de tráfico agke-east-1
. - 60 RPS, que está por sobre la capacidad de los Services en ambos clústeres.
Configurar panel
Obtén el nombre del URLmap subyacente para tu Gateway:
kubectl get gateways.gateway.networking.k8s.io store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
El resultado es similar a este:
gkemcg-traffic-test-store-armvfyupay1t
En la consola de Google Cloud, ve a la página Explorador de métricas.
Haz clic en MQL.
Ingresa la siguiente consulta para observar las métricas de tráfico del Service de almacenamiento 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)]
Reemplaza
GATEWAY_URL_MAP
por el nombre del URLmap del paso anterior.Haga clic en Run query. Espera al menos 5 minutos después de implementar el generador de cargas en la siguiente sección para que las métricas se muestren en el gráfico.
Realiza pruebas con 10 RPS
Implementa 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'
Reemplaza
GATEWAY_IP_ADDRESS
por la dirección IP de la Gateway del paso anterior.El resultado es similar al 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 cargas envía de forma continua 10 RPS a la Gateway. Aunque el tráfico proviene de una región de Google Cloud, el balanceador de cargas lo trata como el tráfico de clientes que proviene de la costa oeste de EE.UU. Para simular una diversidad de clientes realista, el generador de cargas envía cada solicitud HTTP como una conexión TCP nueva, lo que significa que el tráfico se distribuye de manera más uniforme entre los Pods de backend.
El generador tarda hasta 5 minutos en generar tráfico para el panel.
Ve el panel Explorador de métricas. Aparecen dos líneas que indican cuánto tráfico tiene balanceo de cargas en cada clúster:
Deberías ver que
us-west1-a
recibe alrededor de 10 RPS de tráfico, mientras queus-east1-b
no recibe tráfico. Debido a que el generador de tráfico se ejecuta enus-west1
, todo el tráfico se envía al Service en el clústergke-west-1
.Detén el generador de cargas con Ctrl+C y, luego, borra el Pod:
kubectl delete pod loadgen --context=gke-west-1
Realiza pruebas con 30 RPS
Vuelve a implementar el generador de cargas, pero configúralo 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.
Ve el panel de Cloud Ops.
Deberías ver que se envían alrededor de 20 RPS a
us-west1-a
y 10 RPS aus-east1-b
. Esto indica que el Service engke-west-1
se usa por completo y desborda 10 RPS de tráfico al Service engke-east-1
.Detén el generador de cargas con Ctrl+C y, luego, borra el Pod:
kubectl delete pod loadgen --context=gke-west-1
Realiza pruebas con 60 RPS
Implementa el generador de cargas 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 ve tu panel Cloud Ops. Ahora, debería mostrar que ambos clústeres reciben aproximadamente 30 RPS. Dado que todos los Services están sobreutilizados a nivel global, no hay desbordamiento de tráfico y los Services absorben todo el tráfico que pueden.
Detén el generador de cargas con Ctrl+C y, luego, borra el Pod:
kubectl delete pod loadgen --context=gke-west-1
Limpia
Después de completar el ejercicio, sigue estos pasos para quitar los recursos a fin de prevenir cobros no deseados en tu cuenta:
Anula el registro de tus clústeres en la flota si no es necesario que estén registrados para otro propósito.
Inhabilita la función
multiclusterservicediscovery
:gcloud container fleet multi-cluster-services disable
Inhabilitar entrada de varios clústeres
gcloud container fleet ingress disable
Inhabilita las API:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
¿Qué sigue?
- Obtén más información sobre el controlador de Gateway.