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 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 forniscono 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 accesso 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 shopping online è di proprietà e gestito da team separati e viene implementato in una flotta di cluster GKE condivisi.

Prima di iniziare

I gateway multicluster richiedono una 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. Esegui il deployment dei cluster GKE.

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

  3. Abilita i controller del servizio multi-cluster e del gateway multi-cluster.

Infine, esamina le limitazioni e i problemi noti del controller GKE Gateway 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 di traffico tra due cluster GKE.

Questo esempio illustra alcuni passaggi realistici che un proprietario del servizio eseguirebbe 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 il corretto funzionamento del nuovo cluster. Questo esempio illustra quattro fasi di deployment:

  1. 100% - Canary basato sull'intestazione: Utilizza il routing delle intestazioni HTTP per inviare solo traffico di test o sintetico al nuovo cluster.
  2. 100% - Traffico mirror: Duplica il traffico degli utenti nel cluster canary. In questo modo viene testata la capacità del cluster canary copiando il 100% del traffico utenti in questo cluster.
  3. 90%-10%: Canary a traffic split del 10% per esporre lentamente il nuovo cluster al traffico reale.
  4. 0%-100%: Esegui il cutover completo al nuovo cluster con la possibilità di tornare indietro in caso di errori.

Suddivisione del traffico blu/verde tra due cluster GKE

Questo esempio è simile al precedente, tranne per il fatto che viene eseguito il deployment di un gateway multicluster interno. Viene eseguito il deployment di un bilanciatore del carico delle applicazioni interno accessibile privatamente solo dall'interno del VPC. Utilizzerai i cluster e la stessa applicazione che hai eseguito il deployment nei passaggi precedenti, ma eseguirai il deployment tramite un gateway diverso.

Prerequisiti

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

  1. Preparare 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é gke-l7-rilb-mc GatewayClass è regionale e supporta solo i backend dei cluster nella stessa regione.

  3. Esegui il deployment dei servizi e delle ServiceExport necessari su ogni cluster. Se hai eseguito il deployment di Services e ServiceExports dell'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 stai eseguendo 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.

Prima di creare gateway che gestiscono bilanciatori del carico delle applicazioni interni, devi creare una subnet solo proxy. 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 regionale 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 è riuscito 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 sull'intestazione

Il canarying basato sull'intestazione consente al proprietario del servizio di abbinare 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 implementata, questa 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 sul cluster gke-west-1.
    • Le richieste interne a store.example.internal con l'intestazione HTTP env: canary vengono indirizzate ai pod store sul cluster gke-west-2

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

    Verifica che 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 successivi con l'indirizzo IP che ricevi come output.

  3. Invia una richiesta al gateway utilizzando l'intestazione HTTP env: canary. In questo modo verificherai che il traffico venga 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 con 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"
    }
    

Specchio stradale

Questa fase invia il traffico al cluster di destinazione, ma lo duplica anche nel cluster canary.

L'utilizzo del mirroring è utile per determinare in che modo il carico di traffico influirà sulle prestazioni dell'applicazione senza influire in alcun modo sulle risposte ai tuoi clienti. Potrebbe non essere necessario per tutti i tipi di implementazione, ma può essere utile quando si implementano modifiche di grandi dimensioni che potrebbero influire sul rendimento 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 per 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 primario risponde al traffico. Devi comunque confermare che il cluster a cui stai eseguendo la migrazione riceve il traffico mirroring.

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

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Questo output conferma che anche i pod del 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 quelli degli indirizzi 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 nuovo codice o eseguire il deployment in nuovi ambienti in modo sicuro. Il proprietario del servizio imposta una percentuale esplicita di traffico inviato ai backend canary, che in genere è una quantità molto piccola 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.

L'esecuzione di una suddivisione del traffico con una minoranza del traffico consente al proprietario del servizio di ispezionare l'integrità dell'applicazione e le risposte. Se tutti gli indicatori sembrano integri, possono procedere al cutover completo.

  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 a questo, a indicare che si sta verificando 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",
    ...
    

Trasferimento 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 stava effettivamente eseguendo l'onboarding di un secondo cluster in un cluster esistente, questo ultimo passaggio sarebbe diverso in quanto il passaggio finale prevederebbe il traffico verso entrambi i cluster. In questo scenario, è consigliabile un singolo store ServiceImport con pod provenienti dai cluster gke-west-1 e gke-west-2. In questo modo, il bilanciatore del carico può decidere dove deve andare il traffico per un'applicazione active-active, 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 a questo, a indicare che tutto il traffico ora è diretto 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 blue-green da un cluster GKE a un altro cluster GKE.

Esegui la pulizia

Dopo aver completato gli esercizi descritti in 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 devono essere registrati 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:

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

no healthy upstream

Motivo:

Questo messaggio di errore indica che il probe di 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