Esegui il deployment di un gateway multi-cluster per la suddivisione ponderata del traffico

Questo documento ti guida attraverso un deployment blu/verde di un'applicazione store di esempio in due cluster GKE. I deployment blu/verde sono una strategia efficace per eseguire la migrazione delle tue applicazioni a nuovi cluster GKE con un rischio minimo. Spostando gradualmente il traffico dal cluster attuale (blu) al nuovo cluster (verde), puoi convalidare il nuovo ambiente in produzione prima di eseguire un cutover completo.

I gateway multi-cluster offrono un modo efficace per gestire il traffico per i servizi di cui è stato eseguito il deployment in più cluster GKE. Utilizzando l'infrastruttura di bilanciamento del carico globale di Google, puoi creare un unico punto di ingresso per le tue applicazioni, semplificando la gestione e migliorando l'affidabilità.

In questo tutorial utilizzerai un'applicazione store di esempio per simulare uno scenario reale in cui un servizio di acquisti online è di proprietà e gestito da team separati e viene eseguito il deployment in un parco risorse di cluster GKE condivisi.

Prima di iniziare

I gateway multi-cluster richiedono una certa preparazione dell'ambiente prima di poter essere implementati. Prima di procedere, segui i passaggi descritti in Prepara l'ambiente per i gateway multi-cluster:

  1. Eseguire il deployment dei cluster GKE.

  2. Registra i cluster in un parco risorse (se non sono già registrati).

  3. Abilita i controller dei servizi multi-cluster e dei gateway multi-cluster.

Infine, esamina le limitazioni e i problemi noti del GKE Gateway Controller prima di utilizzarlo nel tuo ambiente.

Routing blu/verde multi-cluster con Gateway

Le GatewayClass gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* e gke-l7-rilb-* hanno molte funzionalità avanzate di routing del traffico, tra cui suddivisione del traffico, corrispondenza delle intestazioni, manipolazione delle intestazioni, mirroring del traffico e altro ancora. In questo esempio, mostrerai come utilizzare la suddivisione del traffico basata sul peso per controllare esplicitamente la proporzione del traffico tra due cluster GKE.

Questo esempio illustra alcuni passaggi realistici che un proprietario di un servizio dovrebbe seguire per spostare o espandere la propria applicazione in un nuovo cluster GKE. L'obiettivo dei deployment blu-verde è ridurre il rischio attraverso più passaggi di convalida che confermano che il nuovo cluster funziona correttamente. Questo esempio illustra quattro fasi del deployment:

  1. 100% - Canary basato su intestazione: utilizza il routing delle intestazioni HTTP per inviare solo traffico di test o sintetico al nuovo cluster.
  2. 100% - Traffico di mirroring: esegui il mirroring del traffico utente nel cluster canary. In questo modo, viene testata la capacità del cluster canary copiando il 100% del traffico utente in questo cluster.
  3. 90%-10%: Canary con una suddivisione del traffico del 10% per esporre lentamente il nuovo cluster al traffico in tempo reale.
  4. 0%-100%: esegui il cutover completo al nuovo cluster con l'opzione di tornare indietro se vengono rilevati errori.

Suddivisione del traffico blu/verde tra due cluster GKE

Questo esempio è simile al precedente, ma esegue il deployment di un gateway multi-cluster interno. In questo modo viene eseguito il deployment di un bilanciatore del carico delle applicazioni interno, accessibile solo privatamente dall'interno del VPC. Utilizzerai i cluster e la stessa applicazione di cui hai eseguito il deployment nei passaggi precedenti, ma ne eseguirai il deployment tramite un gateway diverso.

Prerequisiti

L'esempio seguente si basa su alcuni dei passaggi descritti in Deployment di un gateway multi-cluster esterno. Assicurati di aver completato i seguenti passaggi prima di procedere con questo esempio:

  1. Prepara l'ambiente per i gateway multi-cluster

  2. Deployment di un'applicazione demo

    Questo esempio utilizza i cluster gke-west-1 e gke-west-2 che hai già configurato. Questi cluster si trovano nella stessa regione perché la GatewayClass gke-l7-rilb-mc è a livello di regione e supporta solo i backend dei cluster nella stessa regione.

  3. Esegui il deployment del servizio e degli oggetti ServiceExport necessari su ogni cluster. Se hai eseguito il deployment di servizi e ServiceExport dall'esempio precedente, hai già eseguito il deployment di alcuni di questi.

    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
    

    Esegue il deployment di un insieme simile di risorse in ogni cluster:

    service/store created
    serviceexport.net.gke.io/store created
    service/store-west-2 created
    serviceexport.net.gke.io/store-west-2 created
    

Configurazione di una subnet solo proxy

Se non l'hai ancora fatto, configura una subnet solo proxy per ogni regione in cui esegui il deployment dei gateway interni. Questa subnet viene utilizzata per fornire indirizzi IP interni ai proxy del bilanciatore del carico e deve essere configurata con un --purpose impostato solo su REGIONAL_MANAGED_PROXY.

Devi creare una subnet solo proxy prima di creare i gateway che gestiscono i bilanciatori del carico delle applicazioni interni. Ogni regione di una rete Virtual Private Cloud (VPC) in cui utilizzi i bilanciatori del carico delle applicazioni interni deve avere una subnet solo proxy.

Il comando gcloud compute networks subnets create crea una subnet solo proxy.

gcloud compute networks subnets create SUBNET_NAME \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=REGION \
    --network=VPC_NETWORK_NAME \
    --range=CIDR_RANGE

Sostituisci quanto segue:

  • SUBNET_NAME: il nome della subnet solo proxy.
  • REGION: la regione della subnet solo proxy.
  • VPC_NETWORK_NAME: il nome della rete VPC che contiene la subnet.
  • CIDR_RANGE: l'intervallo di indirizzi IP principale della subnet. Devi utilizzare una subnet mask non superiore a /26 in modo che siano disponibili almeno 64 indirizzi IP per i proxy nella regione. La subnet mask consigliata è /23.

Deployment del gateway

Il seguente gateway viene creato dalla GatewayClass gke-l7-rilb-mc, che è un gateway interno a livello di regione che può avere come target solo i cluster GKE nella stessa regione.

  1. Applica il seguente manifest Gateway al cluster di configurazione, gke-west-1 in questo esempio:

    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
    EOF
    
  2. Verifica che il gateway sia stato avviato correttamente. Puoi filtrare solo gli eventi di questo gateway con il seguente comando:

    kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace store
    

    Il deployment del gateway è andato a buon fine se l'output è simile al seguente:

    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 basato su intestazione

La canary basata su intestazione consente al proprietario del servizio di trovare corrispondenze con il traffico di test sintetico che non proviene da utenti reali. Questo è un modo semplice per verificare che il networking di base dell'applicazione funzioni senza esporre direttamente gli utenti.

  1. Applica il seguente manifest HTTPRoute al cluster di configurazione, gke-west-1 in questo esempio:

    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
    EOF
    

    Una volta eseguito il deployment, questa risorsa HTTPRoute configura il seguente comportamento di routing:

    • Le richieste interne a store.example.internal senza l'intestazione HTTP env: canary vengono indirizzate ai pod store nel cluster gke-west-1
    • Le richieste interne a store.example.internal con l'intestazione HTTP env: canary vengono indirizzate ai pod store nel cluster gke-west-2

    HTTPRoute consente il routing a cluster diversi in base alle intestazioni HTTP

    Verifica che la risorsa HTTPRoute funzioni correttamente inviando traffico all'indirizzo IP del gateway.

  2. Recupera l'indirizzo IP interno da internal-http.

    kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace store
    

    Sostituisci VIP nei passaggi seguenti con l'indirizzo IP che ricevi come output.

  3. Invia una richiesta al gateway utilizzando l'intestazione HTTP env: canary. In questo modo, confermerai che il traffico viene indirizzato a gke-west-2. Utilizza un client privato nello stesso VPC dei cluster GKE per verificare che le richieste vengano instradate correttamente. Il seguente comando deve essere eseguito su una macchina che ha accesso privato all'indirizzo IP del gateway, altrimenti non funzionerà.

    curl -H "host: store.example.internal" -H "env: canary" http://VIP
    

    L'output conferma che la richiesta è stata gestita da un pod del cluster 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"
    }
    

Mirroring del traffico

Questa fase invia il traffico al cluster previsto, ma ne esegue anche il mirroring al cluster canary.

L'utilizzo del mirroring è utile per determinare l'impatto del carico di traffico sulle prestazioni dell'applicazione senza influire in alcun modo sulle risposte ai client. Potrebbe non essere necessario per tutti i tipi di implementazioni, ma può essere utile quando si implementano modifiche di grandi dimensioni che potrebbero influire sulle prestazioni o sul carico.

  1. Applica il seguente manifest HTTPRoute al cluster di configurazione, gke-west-1 in questo esempio:

    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
    EOF
    
  2. Utilizzando il tuo client privato, invia una richiesta al gateway internal-http. Utilizza il percorso /mirror in modo da poter identificare in modo univoco questa richiesta nei log dell'applicazione in un passaggio successivo.

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. L'output conferma che il client ha ricevuto una risposta da un pod nel cluster 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"
    }
    

    Ciò conferma che il cluster principale risponde al traffico. Devi comunque confermare che il cluster di cui stai eseguendo la migrazione riceva il traffico sottoposto a mirroring.

  4. Controlla i log dell'applicazione di un pod store nel cluster gke-west-2. I log dovrebbero confermare che il pod ha ricevuto il traffico sottoposto a mirroring dal bilanciatore del carico.

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Questo output conferma che anche i pod nel cluster gke-west-2 ricevono le stesse richieste, ma le loro risposte a queste richieste non vengono inviate al client. Gli indirizzi IP visualizzati nei log sono gli IP interni del bilanciatore del carico che comunicano con i tuoi pod.

    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 -
    

Suddivisione traffico

La suddivisione del traffico è uno dei metodi più comuni per implementare un nuovo codice o eseguire il deployment in nuovi ambienti in modo sicuro. Il proprietario del servizio imposta una percentuale esplicita di traffico che viene inviata ai backend canary, che in genere rappresenta una quantità molto ridotta del traffico complessivo, in modo che il successo dell'implementazione possa essere determinato con un livello di rischio accettabile per le richieste degli utenti reali.

La suddivisione del traffico con una minoranza del traffico consente al proprietario del servizio di ispezionare l'integrità dell'applicazione e le risposte. Se tutti i segnali sono positivi, possono procedere al cutover.

  1. Applica il seguente manifest HTTPRoute al cluster di configurazione, gke-west-1 in questo esempio:

    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
    EOF
    
  2. Utilizzando il tuo client privato, invia una richiesta curl continua al gateway internal- http.

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    L'output sarà simile al seguente, a indicare che è in corso una suddivisione del traffico 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",
    ...
    

Cutover del traffico

L'ultima fase della migrazione blu/verde consiste nel passare completamente al nuovo cluster e rimuovere quello precedente. Se il proprietario del servizio stesse effettivamente eseguendo l'onboarding di un secondo cluster in un cluster esistente, quest'ultimo passaggio sarebbe diverso, poiché il passaggio finale prevederebbe il traffico verso entrambi i cluster. In questo scenario, è consigliabile un singolo ServiceImport store con pod di entrambi i cluster gke-west-1 e gke-west-2. In questo modo, il bilanciatore del carico può decidere dove indirizzare il traffico per un'applicazione attiva-attiva, in base a prossimità, integrità e capacità.

  1. Applica il seguente manifest HTTPRoute al cluster di configurazione, gke-west-1 in questo esempio:

    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
    EOF
    
  2. Utilizzando il tuo client privato, invia una richiesta curl continua al gateway internal- http.

    while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; done
    

    L'output sarà simile al seguente, a indicare che tutto il traffico ora va a gke-west-2.

    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    "cluster_name": "gke-west-2",
    ...
    

Questo passaggio finale completa una migrazione completa dell'applicazione blu-verde da un cluster GKE a un altro cluster GKE.

Esegui la pulizia

Dopo aver completato gli esercizi di questo documento, segui questi passaggi per rimuovere le risorse ed evitare addebiti indesiderati sul tuo account:

  1. Elimina i cluster.

  2. Annulla la registrazione dei cluster dal parco risorse se non è necessario registrarli per un altro scopo.

  3. Disattiva la funzionalità multiclusterservicediscovery:

    gcloud container fleet multi-cluster-services disable
    
  4. Disabilita Ingress multi-cluster:

    gcloud container fleet ingress disable
    
  5. Disabilita le API:

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

Risoluzione dei problemi

Nessun upstream integro

Sintomo:

Il seguente problema potrebbe verificarsi quando crei un gateway, ma non riesci ad accedere ai servizi di backend (codice di risposta 503):

no healthy upstream

Motivo:

Questo messaggio di errore indica che il controllo di integrità non riesce a trovare servizi di backend integri. È possibile che i servizi di backend siano integri, ma potrebbe essere necessario personalizzare i controlli di integrità.

Soluzione temporanea:

Per risolvere il problema, personalizza il controllo di integrità in base ai requisiti della tua applicazione (ad esempio /health) utilizzando un HealthCheckPolicy.

Passaggi successivi