En este documento, se te guía a través de una implementación azul-verde de una aplicación de store de muestra en dos clústeres de GKE. Las implementaciones azul-verde son una estrategia eficaz para migrar tus aplicaciones a clústeres nuevos de GKE con un riesgo mínimo. Si cambias el tráfico de forma gradual del clúster actual (azul) al clúster nuevo (verde), puedes validar el entorno nuevo en producción antes de confirmar un cambio completo.
En este instructivo, usarás una aplicación de ejemplo de store para simular una situación real en la que un servicio de compras en línea es propiedad de equipos independientes y está operado por ellos, y se implementa en una flota de clústeres de GKE compartidos.
Antes de comenzar
Las puertas de enlace de varios clústeres requieren cierta preparación del entorno antes de que puedan implementarse. Antes de continuar, sigue los pasos que se indican en Prepara tu entorno para las puertas de enlace de varios clústeres:
Implemente clústeres de GKE
Registra tus clústeres en una flota (si aún no lo hiciste).
Habilita el Service de varios clústeres y los controladores de puertas de enlace de varios clústeres.
Por último, revisa las limitaciones y los problemas conocidos del controlador de puerta de enlace de GKE antes de usarlo en tu entorno.
Enrutamiento azul-verde y de varios clústeres con puerta de enlace
Las GatewayClasses gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* y gke-l7-rilb-* 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 puerta de enlace de varios clústeres interna en su lugar. De esta manera, se implementa un balanceador de cargas 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 implementaste en los pasos anteriores, con la excepción de que los implementarás a través de una puerta de enlace diferente.
Requisitos previos
El siguiente ejemplo se basa en algunos de los pasos de Implementa una puerta de enlace de varios clústeres externa. Antes de continuar con este ejemplo, asegúrate de haber realizado los siguientes pasos:
Prepara tu entorno para las puertas de enlace de varios clústeres
Implementa una aplicación de demostración
En este ejemplo, se usan los clústeres
gke-west-1ygke-west-2que ya configuraste. Estos clústeres están en la misma región porque GatewayClassgke-l7-rilb-mces 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.yamlImplementa 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 y debe configurarse solo con un --purpose configurado como REGIONAL_MANAGED_PROXY.
Debes crear una subred de solo proxy antes de crear puertas de enlace con las que se administren los balanceadores de cargas de aplicaciones internos. Cada región de una red de nube privada virtual (VPC) en la que uses balanceadores de cargas de aplicaciones 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/26a 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.
Implementa la Gateway
La siguiente puerta de enlace se crea a partir de la GatewayClass gke-l7-rilb-mc, que es una puerta de enlace interna regional que solo puede segmentar clústeres de GKE en la misma región.
Aplica el siguiente manifiesto
Gatewayal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-http namespace: store spec: gatewayClassName: gke-l7-rilb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOFVerifica que la puerta de enlace haya aparecido correctamente. Puedes filtrar solo los eventos de esta puerta de enlace con el siguiente comando:
kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace storeLa implementación de la puerta de enlace se realizó de forma correcta 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
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.
Aplica el siguiente manifiesto
HTTPRouteal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: 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 EOFUna vez implementado, este HTTPRoute configura el siguiente comportamiento de enrutamiento:
- Las solicitudes internas a
store.example.internalsin el encabezado HTTPenv: canaryse enrutan a los Podsstoreen el clústergke-west-1. - Las solicitudes internas a
store.example.internalcon el encabezado HTTPenv: canaryse enrutan a los Podsstoreen el clústergke-west-2.
Envía tráfico a la dirección IP de la puerta de enlace para validar que la HTTPRoute funcione correctamente.
- 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 storeReemplaza VIP en los siguientes pasos por la dirección IP que recibas como resultado.
Envía una solicitud a la puerta de enlace 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 la puerta de enlace o no funcionará.curl -H "host: store.example.internal" -H "env: canary" http://VIPEl 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.
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.
Aplica el siguiente manifiesto
HTTPRouteal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: 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 EOFCon tu cliente privado, envía una solicitud a la puerta de enlace
internal-http. Usa la ruta de acceso/mirrorpara 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/mirrorEl 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
storeen 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 /mirrorEste resultado confirma que los Pods en el clúster
gke-west-2tambié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-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 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.
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.
Aplica el siguiente manifiesto
HTTPRouteal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: 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 EOFCon tu cliente privado, envía una solicitud curl continua a la puerta de enlace
internal- http.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; doneEl 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", ...
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 con el balanceador de cargas se puede decidir a dónde debe dirigirse el tráfico para una aplicación activa-activa, según la proximidad, el estado y la capacidad.
Aplica el siguiente manifiesto
HTTPRouteal clúster de configuración,gke-west-1en este ejemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: 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 EOFCon tu cliente privado, envía una solicitud curl continua a la puerta de enlace
internal- http.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; doneEl 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.
Realiza una limpieza
Después de completar los ejercicios de este documento, 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 disableInhabilitar entrada de varios clústeres
gcloud container fleet ingress disableInhabilita las API:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
Soluciona problemas
Sin upstream en buen estado
Síntoma:
El siguiente problema puede ocurrir cuando creas una puerta de enlace, pero no puedes acceder a los servicios de backend (código de respuesta 503):
no healthy upstream
Motivo:
Este mensaje de error indica que el sistema de sondeo de verificación de estado no puede encontrar servicios de backend en buen estado. Es posible que tus servicios de backend estén en buen estado, pero es posible que debas personalizar las verificaciones de estado.
Solución alternativa:
Para resolver este problema, personaliza la verificación de estado según los requisitos de tu aplicación (por ejemplo, /health) mediante un HealthCheckPolicy.
¿Qué sigue?
- Obtén más información sobre el controlador de puerta de enlace.