Déployer une passerelle multicluster pour la répartition du trafic pondérée

Ce document vous guide dans le déploiement bleu-vert d'un exemple d'application store sur deux clusters GKE. Les déploiements bleu-vert constituent une stratégie efficace pour migrer vos applications vers de nouveaux clusters GKE avec un risque minimal. En transférant progressivement le trafic du cluster actuel (bleu) vers le nouveau cluster (vert), vous pouvez valider le nouvel environnement en production avant de vous engager dans une transition complète.

Les passerelles multiclusters constituent un moyen efficace de gérer le trafic des services déployés sur plusieurs clusters GKE. En utilisant l'infrastructure d'équilibrage de charge mondial de Google, vous pouvez créer un point d'entrée unique pour vos applications, ce qui simplifie la gestion et améliore la fiabilité.

Dans ce tutoriel, vous utiliserez un exemple d'application store pour simuler un scénario réel dans lequel un service d'achats en ligne est détenu et géré par des équipes distinctes, et est déployé sur un parc de clusters GKE partagés.

Avant de commencer

Les passerelles multiclusters nécessitent une préparation environnementale avant de pouvoir être déployées. Avant de continuer, suivez les étapes décrites dans la section Préparer votre environnement pour les passerelles multiclusters :

  1. Déployez des clusters GKE

  2. Enregistrez vos clusters dans un parc (si ce n'est pas déjà fait).

  3. Activez les contrôleurs de service et de passerelle multiclusters.

Enfin, consultez les limites et les problèmes connus du contrôleur GKE Gateway avant de l'utiliser dans votre environnement.

Routage multicluster bleu-vert avec une passerelle

Les passerelles gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* et gke-l7-rilb-* disposent de nombreuses fonctionnalités avancées de routage du trafic comme la répartition du trafic, la mise en correspondance des en-têtes, la manipulation des en-têtes, la mise en miroir du trafic, etc… Dans cet exemple, vous apprendrez à utiliser la répartition du trafic basée sur une pondération pour contrôler explicitement la proportion de trafic envoyée aux deux clusters GKE.

Cet exemple décrit certaines des étapes réelles qu'un propriétaire de service doit effectuer pour déplacer ou étendre son application vers un nouveau cluster GKE. L'objectif des déploiements bleu-vert est de réduire les risques grâce à plusieurs étapes de validation qui confirment que le nouveau cluster fonctionne correctement. Cet exemple décrit quatre étapes de déploiement :

  1. 100%Canary basé sur l'en-tête : utilisez le routage d'en-tête HTTP pour envoyer uniquement le trafic de test ou de synthèse vers le nouveau cluster.
  2. 100% - Mise en miroir du trafic : mettez en miroir le trafic utilisateur vers le cluster Canary. Cela permet de tester la capacité du cluster Canary en copiant 100 % du trafic utilisateur vers ce cluster.
  3. 90 %-10 %  : répartition du trafic Canary de 10 % pour exposer progressivement le nouveau cluster vers le trafic en temps réel.
  4. 0 % - 100 % : basculer complète vers le nouveau cluster avec la possibilité de revenir en arrière si des erreurs sont observées.

Répartition bleu-vert du trafic sur deux clusters GKE

Cet exemple est semblable au précédent mais il utilise une passerelle multicluster interne. Il consiste à déployer un équilibreur de charge d'application interne qui n'est accessible que de manière privée depuis le VPC. Vous allez utilisez les clusters et l'application déployés lors des étapes précédentes mais les déployer via une autre passerelle.

Prérequis

L'exemple suivant s'appuie sur certaines des étapes de la section Déployer une passerelle multicluster externe. Assurez-vous d'avoir suivi les étapes suivantes avant de continuer avec cet exemple :

  1. Préparer votre environnement pour les passerelles multiclusters

  2. Déployer une application de démonstration

    Cet exemple utilise les clusters gke-west-1 et gke-west-2 que vous avez déjà configurés. Ces clusters se trouvent dans la même région, car la ressource GatewayClass gke-l7-rilb-mc est régionale et n'accepte que les backends de cluster situés dans la même région.

  3. Déployez les ressources Service et ServiceExport nécessaires sur chaque cluster. Si vous avez déployé des ressources Service et ServiceExport pour l'exemple précédent, vous avez déjà déployé certaines des ressources nécessaires.

    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
    

    Cela déploie un ensemble de ressources similaire sur chaque cluster :

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

Configurer un sous-réseau proxy réservé

Si vous ne l'avez pas déjà fait, configurez un sous-réseau proxy réservé pour chaque région dans laquelle vous déployez des passerelles internes. Ce sous-réseau permet de fournir des adresses IP internes aux proxys des équilibreurs de charge et doit être configuré avec un --purpose défini sur REGIONAL_MANAGED_PROXY uniquement.

Vous devez créer un sous-réseau proxy réservé avant de créer des passerelles gérant des équilibreurs de charge d'application internes. Chaque région d'un réseau cloud privé virtuel (VPC) dans lequel vous utilisez des équilibreurs de charge d'application internes doit comporter un sous-réseau proxy réservé.

La commande gcloud compute networks subnets create crée un sous-réseau proxy réservé.

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

Remplacez les éléments suivants :

  • SUBNET_NAME : nom du sous-réseau proxy réservé.
  • REGION : région du sous-réseau proxy réservé.
  • VPC_NETWORK_NAME : nom du réseau VPC contenant le sous-réseau.
  • CIDR_RANGE : plage d'adresses IP principale du sous-réseau. Vous devez utiliser un masque de sous-réseau ne dépassant pas /26 afin qu'au moins 64 adresses IP soient disponibles pour les proxys de la région. Le masque de sous-réseau recommandé est /23.

Déployer la passerelle

La passerelle suivante est créée à partir de la GatewayClass gke-l7-rilb-mc, qui est une passerelle interne régionale ne pouvant cibler que les clusters GKE de la même région.

  1. Appliquez le fichier manifeste Gateway suivant au cluster de configuration, gke-west-1 dans cet exemple :

    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. Vérifiez que la passerelle est bien opérationnelle. Vous pouvez filtrer uniquement les événements de cette passerelle en utilisant la commande suivante :

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

    Le déploiement de la passerelle a réussi si le résultat ressemble à ce qui suit :

    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 basé sur l'en-tête

La version Canary basée sur l'en-tête permet au propriétaire du service de mettre en correspondance le trafic de test synthétique qui ne provient pas d'utilisateurs réels. Cela vous permet de vérifier facilement que le réseau de base de l'application fonctionne sans exposer directement les utilisateurs.

  1. Appliquez le fichier manifeste HTTPRoute suivant au cluster de configuration, gke-west-1 dans cet exemple :

    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
    

    Une fois déployé, cet objet HTTPRoute configure le comportement de routage suivant :

    • Les requêtes internes envoyées à store.example.internal sans l'en-tête HTTP env: canary sont acheminées vers les pods store sur le cluster gke-west-1.
    • Les requêtes internes envoyées à store.example.internal avec l'en-tête HTTP env: canary sont acheminées vers les pods store sur le cluster gke-west-2.

    HTTPRoute permet de router les requêtes vers différents clusters en fonction des en-têtes HTTP.

    Vérifiez que l'objet HTTPRoute fonctionne correctement en envoyant du trafic vers l'adresse IP de la passerelle.

  2. Récupérez l'adresse IP interne de internal-http.

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

    Dans les étapes suivantes, remplacez VIP par l'adresse IP que vous recevez en sortie.

  3. Envoyez une requête à la passerelle en utilisant l'en-tête HTTP env: canary. Cela confirme que le trafic est acheminé vers gke-west-2. Utilisez un client privé dans le même VPC que les clusters GKE afin de vérifier que les requêtes sont correctement acheminées. La commande suivante doit être exécutée sur une machine disposant d'un accès privé à l'adresse IP de la passerelle, sans quoi elle ne fonctionnera pas.

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

    Le résultat confirme que la requête a été diffusée par un pod à partir du 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"
    }
    

Mise en miroir du trafic

Cette étape envoie le trafic vers le cluster prévu, mais met également en miroir ce trafic vers le cluster Canary.

La mise en miroir permet de déterminer l'impact de la charge de trafic sur les performances de l'application, sans aucun impact sur les réponses fournies à vos clients. Elle n'est pas nécessaire pour tous les types de déploiements, mais elle peut être utile lors du déploiement de modifications importantes susceptibles d'affecter les performances ou la charge.

  1. Appliquez le fichier manifeste HTTPRoute suivant au cluster de configuration, gke-west-1 dans cet exemple :

    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. À l'aide de votre client privé, envoyez une requête à la passerelle internal-http. Utilisez le chemin /mirror pour identifier de manière unique cette requête dans les journaux d'application lors d'une prochaine étape.

    curl -H "host: store.example.internal" http://VIP/mirror
    
  3. Le résultat confirme que le client a reçu une réponse d'un pod du 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"
    }
    

    Cela confirme que le cluster principal répond bien au trafic. Vous devez toujours vérifier que le cluster vers lequel vous effectuez la migration reçoit le trafic mis en miroir.

  4. Vérifiez les journaux d'application d'un pod store sur le cluster gke-west-2. Les journaux doivent confirmer que le pod a bien reçu le trafic mis en miroir de l'équilibreur de charge.

    kubectl logs deployment/store --context gke-west-2 -n store | grep /mirror
    
  5. Ce résultat confirme que les pods du cluster gke-west-2 reçoivent également les mêmes requêtes, mais que leurs réponses à ces requêtes ne sont pas renvoyées au client. Les adresses IP affichées dans les journaux sont les adresses IP internes de l'équilibreur de charge interne qui communique avec vos 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 -
    

Répartition du trafic

La répartition du trafic est l'une des méthodes les plus courantes pour déployer du nouveau code ou effectuer des déploiements en toute sécurité dans de nouveaux environnements. Le propriétaire du service définit un pourcentage explicite de trafic envoyé aux backends Canary, généralement une petite partie du trafic global, afin de déterminer la réussite du déploiement avec une quantité acceptable de risque pour les requêtes réelles des utilisateurs.

Une répartition du trafic avec une petite partie du trafic permet au propriétaire du service d'inspecter l'état de l'application et des réponses. Si tous les signaux semblent opérationnels, il est possible de passer au basculement complet.

  1. Appliquez le fichier manifeste HTTPRoute suivant au cluster de configuration, gke-west-1 dans cet exemple :

    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. À l'aide de votre client privé, envoyez une requête curl continue à la passerelle internal- http.

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

    Le résultat sera semblable à ceci, indiquant qu'une répartition du trafic de 90/10 est appliquée.

    "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",
    ...
    

Basculement du trafic

La dernière étape de la migration bleu-vert consiste à basculer entièrement vers le nouveau cluster et à supprimer l'ancien cluster. Si le propriétaire du service était en train d'intégrer un deuxième cluster à un cluster existant, cette dernière étape serait différente, car elle consisterait à répartir le trafic entre les deux clusters. Dans ce scénario, il est recommandé d'utiliser une seule ressource ServiceImport store comportant des pods provenant des clusters gke-west-1 et gke-west-2. Cela permet à l'équilibreur de charge de prendre la décision d'acheminement du trafic pour une application en mode actif/actif, en se basant sur la proximité, l'état et la capacité.

  1. Appliquez le fichier manifeste HTTPRoute suivant au cluster de configuration, gke-west-1 dans cet exemple :

    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. À l'aide de votre client privé, envoyez une requête curl continue à la passerelle internal- http.

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

    Le résultat sera semblable à ceci, indiquant que tout le trafic est maintenant dirigé vers gke-west-2.

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

Cette dernière étape vient clôturer le processus de migration bleu-vert complet d'une application, d'un cluster GKE vers un autre cluster GKE.

Effectuer un nettoyage

Après avoir terminé les exercices de ce document, procédez comme suit pour supprimer les ressources afin d'éviter que des frais inutiles ne vous soient facturés sur votre compte :

  1. Supprimer les clusters

  2. Annulez l'enregistrement de vos clusters dans le parc s'ils n'ont pas besoin d'être enregistrés à d'autres fins.

  3. Désactivez la fonctionnalité multiclusterservicediscovery :

    gcloud container fleet multi-cluster-services disable
    
  4. Désactiver un objet Ingess multicluster

    gcloud container fleet ingress disable
    
  5. Désactivez les API :

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

Dépannage

Aucun élément opérationnel en amont

Symptôme :

Le problème suivant peut se produire lorsque vous créez une passerelle, mais que vous ne pouvez pas accéder aux services de backend (code de réponse 503) :

no healthy upstream

Explication :

Ce message d'erreur indique que le vérificateur d'état ne parvient pas à trouver des services de backend opérationnels. Il est possible que vos services de backend soient opérationnels, mais que vous deviez personnaliser les vérifications d'état.

Solution :

Pour résoudre ce problème, personnalisez votre vérification d'état en fonction des exigences de votre application (par exemple, /health), à l'aide d'une ressource HealthCheckPolicy.

Étapes suivantes