En este documento se explica cómo realizar un despliegue azul-verde de una aplicación de ejemplo store
en dos clústeres de GKE. Las implementaciones azul-verde son una estrategia eficaz para migrar tus aplicaciones a nuevos clústeres de GKE con un riesgo mínimo. Si transfieres el tráfico gradualmente del clúster actual (azul) al nuevo (verde), puedes validar el nuevo entorno en producción antes de completar el cambio.
En este tutorial, usarás una aplicación store de ejemplo para simular una situación real en la que un servicio de compras online es propiedad de equipos independientes y está gestionado por ellos, y se despliega en una flota de clústeres de GKE compartidos.
Antes de empezar
Las pasarelas multiclúster requieren cierta preparación del entorno antes de poder implementarse. Antes de continuar, sigue los pasos que se indican en el artículo Preparar el entorno para usar Gateways multiclúster:
Despliega clústeres de GKE.
Registra tus clústeres en una flota (si aún no lo has hecho).
Habilita los controladores de servicio y de pasarela de varios clústeres.
Por último, consulta las limitaciones y los problemas conocidos del controlador de Gateway de GKE antes de usarlo en tu entorno.
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 los riesgos mediante varios pasos de validación que confirmen 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%: duplica el tráfico: duplica 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 aplicación 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 implementado en los pasos anteriores, pero los implementará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-1ygke-west-2que ya has configurado. Estos clústeres están en la misma región porquegke-l7-rilb-mcGatewayClass es regional y solo admite back-ends de clúster en la misma región.Despliega los servicios y ServiceExports necesarios en cada clúster. Si has implementado los servicios y las exportaciones de servicios 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.yamlDespliega 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/26para 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
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 EOFValida que la pasarela se ha 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 storeEl 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
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 dirigen a los podsstoredel clústergke-west-1. - Las solicitudes internas a
store.example.internalcon el encabezado HTTPenv: canaryse dirigen a los podsstoredel 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 storeSustituye 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 puerta de enlace. De lo contrario, no funcionará.curl -H "host: store.example.internal" -H "env: canary" http://VIPEl 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 canary.
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
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 pasarela
internal-http. Usa la ruta/mirrorpara 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 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 reflejado.
Consulta los registros de aplicaciones de un pod
storeen 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 /mirrorEsta salida confirma que los pods del clúster
gke-west-2tambié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 implementar código nuevo o 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 lanzamiento de versiones 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 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 proceder al cambio completo.
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
internal- httpGateway.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á 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 único 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
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
internal- httpGateway.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 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.
Limpieza
Después de completar los ejercicios de este documento, siga estos pasos para quitar recursos y evitar que se apliquen cargos no deseados a su cuenta:
Anula el registro de los clústeres de la flota si no es necesario que estén registrados para otro propósito.
Para inhabilitar la función
multiclusterservicediscovery, sigue estos pasos:gcloud container fleet multi-cluster-services disableInhabilita la entrada de varios clústeres:
gcloud container fleet ingress disableInhabilita las APIs:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
Solución de problemas
No hay upstream en buen estado
Síntoma:
El siguiente problema puede producirse cuando crea una pasarela, pero no puede acceder a los servicios de backend (código de respuesta 503):
no healthy upstream
Motivo:
Este mensaje de error indica que el comprobador de estado no puede encontrar servicios de backend en buen estado. Es posible que tus servicios de backend estén en buen estado, pero que tengas que personalizar las comprobaciones del estado.
Solución alternativa:
Para solucionar este problema, personaliza la comprobación de estado según los requisitos de tu aplicación (por ejemplo, /health) mediante un HealthCheckPolicy.