De la périphérie au réseau multicluster : déployez des applications distribuées à l'échelle mondiale via GKE Gateway et Cloud Service Mesh

Last reviewed 2024-06-30 UTC

Ce document vous explique comment effectuer les tâches suivantes :

Ce guide de déploiement est destiné aux administrateurs de plate-forme. Il s'adresse également aux professionnels avancés qui exécutent Cloud Service Mesh. Ces instructions fonctionnent également pour Istio sur GKE.

Architecture

Le schéma suivant illustre la topologie d'entrée par défaut d'un maillage de services, à savoir un équilibreur de charge TCP/UDP externe qui expose les proxys de passerelle d'entrée sur un seul cluster :

Un équilibreur de charge externe achemine les clients externes vers le maillage via des proxys de passerelle d'entrée.

Ce guide de déploiement utilise les ressources Gateway de Google Kubernetes Engine (GKE). Plus précisément, il utilise une passerelle multicluster pour configurer l'équilibrage de charge multirégional devant plusieurs clusters Autopilot qui sont répartis sur deux régions.

Chiffrement TLS à partir du client, d'un équilibreur de charge et du réseau maillé.

Le schéma précédent montre comment les données transitent par des scénarios d'entrée cloud et d'entrée de maillage. Pour en savoir plus, consultez l'explication du diagramme d'architecture dans la documentation de l'architecture de référence associée.

Objectifs

  • Déployez une paire de clusters GKE Autopilot sur Google Cloud dans le même parc.
  • Déployer un service Cloud Service Mesh basé sur Istio sur le même parc.
  • Configurer un équilibreur de charge à l'aide de GKE Gateway pour interrompre le trafic HTTPS public.
  • Diriger le trafic HTTPS public vers des applications hébergées par Cloud Service Mesh déployées sur plusieurs clusters et régions.
  • Déployer l'exemple d'application whereami sur les deux clusters Autopilot.

Optimisation des coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  3. Dans la console Google Cloud, activez Cloud Shell.

    Activer Cloud Shell

    Vous exécutez toutes les commandes de terminal de ce déploiement depuis Cloud Shell.

  4. Définissez votre projet Google Cloud par défaut :

    export PROJECT=YOUR_PROJECT
    export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)")
    gcloud config set project PROJECT_ID
    

    Remplacez PROJECT_ID par l'ID du projet que vous souhaitez utiliser pour ce déploiement.

  5. Créez un répertoire de travail :

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    

Créer des clusters GKE

Dans cette section, vous allez créer des clusters GKE pour héberger les applications et l'infrastructure de soutien, que vous créerez plus loin dans le présent guide de déploiement.

  1. Dans Cloud Shell, créez un fichier kubeconfig. Cette étape vous permet de ne pas créer de conflit avec votre fichier kubeconfig (par défaut) existant.

    touch edge2mesh_mr_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
    
  2. Définissez les variables d'environnement utilisées lors de la création des clusters GKE et des ressources qu'ils contiennent. Modifiez les choix de région par défaut en fonction de vos besoins.

    export CLUSTER_1_NAME=edge-to-mesh-01
    export CLUSTER_2_NAME=edge-to-mesh-02
    export CLUSTER_1_REGION=us-central1
    export CLUSTER_2_REGION=us-east4
    export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
    
  3. Activez les API Google Cloud utilisées tout au long de ce guide :

    gcloud services enable \
      container.googleapis.com \
      mesh.googleapis.com \
      gkehub.googleapis.com \
      multiclusterservicediscovery.googleapis.com \
      multiclusteringress.googleapis.com \
      trafficdirector.googleapis.com \
      certificatemanager.googleapis.com
    
  4. Créez un cluster GKE Autopilot avec des nœuds privés dans CLUSTER_1_REGION. Utilisez l'option --async pour éviter d'attendre que le premier cluster soit provisionné et enregistré dans le parc :

    gcloud container clusters create-auto --async \
    ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \
    --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
    --enable-private-nodes --enable-fleet
    
  5. Créez et enregistrez un deuxième cluster Autopilot dans CLUSTER_2_REGION :

    gcloud container clusters create-auto \
    ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \
    --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
    --enable-private-nodes --enable-fleet
    
  6. Assurez-vous que les clusters sont en cours d'exécution. Un délai de 20 minutes peut être nécessaire avant que tous les clusters ne soient en cours d'exécution :

    gcloud container clusters list
    

    Le résultat ressemble à ce qui suit :

    NAME             LOCATION     MASTER_VERSION  MASTER_IP       MACHINE_TYPE  NODE_VERSION    NUM_NODES  STATUS
    edge-to-mesh-01  us-central1  1.27.5-gke.200  34.27.171.241   e2-small      1.27.5-gke.200             RUNNING
    edge-to-mesh-02  us-east4     1.27.5-gke.200  35.236.204.156  e2-small      1.27.5-gke.200             RUNNING
    
  7. Rassemblez les identifiants de CLUSTER_1_NAME. Vous avez créé CLUSTER_1_NAME de manière asynchrone afin de pouvoir exécuter des commandes supplémentaires pendant le provisionnement du cluster.

    gcloud container clusters get-credentials ${CLUSTER_1_NAME} \
        --region ${CLUSTER_1_REGION}
    
  8. Pour clarifier les noms des contextes Kubernetes, renommez-les avec les noms des clusters :

    kubectl config rename-context gke_PROJECT_ID_${CLUSTER_1_REGION}_${CLUSTER_1_NAME} ${CLUSTER_1_NAME}
    kubectl config rename-context gke_PROJECT_ID_${CLUSTER_2_REGION}_${CLUSTER_2_NAME} ${CLUSTER_2_NAME}
    

Installer un maillage de services

Dans cette section, vous configurez le service Cloud Service Mesh géré avec l'API Fleet. L'utilisation de l'API Fleet pour activer Cloud Service Mesh fournit une approche déclarative permettant de provisionner un maillage de services.

  1. Dans Cloud Shell, activez Cloud Service Mesh sur le parc :

    gcloud container fleet mesh enable
    
  2. Activez la gestion automatique du plan de contrôle et du plan de données :

    gcloud container fleet mesh update \
      --management automatic \
      --memberships ${CLUSTER_1_NAME},${CLUSTER_2_NAME}
    
  3. Patientez 20 minutes environ. Vérifiez ensuite que l'état du plan de contrôle est ACTIVE :

    gcloud container fleet mesh describe
    

    Le résultat ressemble à ce qui suit :

    createTime: '2023-11-30T19:23:21.713028916Z'
    membershipSpecs:
      projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
        mesh:
          management: MANAGEMENT_AUTOMATIC
      projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
        servicemesh:
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: ISTIOD
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
         code: OK
          description: |-
            Revision ready for use: asm-managed-rapid.
            All Canonical Services have been reconciled successfully.
          updateTime: '2024-06-27T09:00:21.333579005Z'
      projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
        servicemesh:
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: ISTIOD
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: |-
            Revision ready for use: asm-managed-rapid.
            All Canonical Services have been reconciled successfully.
          updateTime: '2024-06-27T09:00:24.674852751Z'
    name: projects/e2m-private-test-01/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    spec: {}
    updateTime: '2024-06-04T17:16:28.730429993Z'
    

Déployer un équilibreur de charge d'application externe et créer des passerelles d'entrée

Dans cette section, vous allez déployer un équilibreur de charge d'application externe via le GKE Gateway Controller et créer des passerelles d'entrée pour les deux clusters. Les ressources gateway et gatewayClass automatisent le provisionnement de l'équilibreur de charge et la vérification d'état du backend. Pour fournir la terminaison TLS sur l'équilibreur de charge, vous devez créer des ressources du gestionnaire de certificats et les associer à l'équilibreur de charge. De plus, vous utilisez Cloud Endpoints pour provisionner automatiquement un nom DNS public pour l'application.

Installer une passerelle d'entrée sur les deux clusters

Pour des raisons de sécurité, nous vous recommandons de déployer la passerelle d'entrée dans un espace de noms différent du plan de contrôle maillé.

  1. Dans Cloud Shell, créez un espace de noms asm-ingress dédié sur chaque cluster :

    kubectl --context=${CLUSTER_1_NAME} create namespace asm-ingress
    kubectl --context=${CLUSTER_2_NAME} create namespace asm-ingress
    
  2. Ajoutez un libellé d'espace de noms à l'espace de noms asm-ingress :

    kubectl --context=${CLUSTER_1_NAME} label namespace asm-ingress istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} label namespace asm-ingress istio-injection=enabled
    

    Le résultat ressemble à ce qui suit :

    namespace/asm-ingress labeled
    

    L'ajout d'un libellé istio-injection=enabled aux espaces de noms asm-ingress indique à Cloud Service Mesh d'injecter automatiquement des proxys side-car Envoy lors du déploiement d'un pod.

  3. Générez un certificat autosigné pour une utilisation ultérieure :

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.PROJECT_ID.cloud.goog/O=Edge2Mesh Inc" \
     -keyout ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     -out ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    

    Le certificat fournit une couche de chiffrement supplémentaire entre l'équilibreur de charge et les passerelles d'entrée du maillage de services. Il permet également d'utiliser les protocoles basés sur HTTP/2, tels que gRPC. Les instructions pour associer le certificat autosigné aux passerelles d'entrée sont fournies plus loin dans la section Créer une adresse IP externe, un enregistrement DNS et des ressources de certificat TLS.

    Pour en savoir plus sur les exigences du certificat de passerelle d'entrée, consultez la section Chiffrement entre l'équilibreur de charge et les backends.

  4. Créez un secret Kubernetes sur chaque cluster pour stocker le certificat autosigné :

    kubectl --context ${CLUSTER_1_NAME} -n asm-ingress create secret tls \
     edge2mesh-credential \
     --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    kubectl --context ${CLUSTER_2_NAME} -n asm-ingress create secret tls \
     edge2mesh-credential \
     --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    
  5. Pour procéder à l'intégration à l'équilibreur de charge d'application externe, créez une variante kustomize pour configurer les ressources de passerelle d'entrée :

    mkdir -p ${WORKDIR}/asm-ig/base
    
    cat <<EOF > ${WORKDIR}/asm-ig/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/anthos-service-mesh-samples/docs/ingress-gateway-asm-manifests/base
    EOF
    
    mkdir ${WORKDIR}/asm-ig/variant
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/role.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/rolebinding.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/service-proto-type.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      ports:
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      - name: http
        port: 80
        targetPort: 8080
        appProtocol: HTTP
      - name: https
        port: 443
        targetPort: 8443
        appProtocol: HTTP2
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/gateway.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
     servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, as SNI isn't passed from GFE
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/kustomization.yaml
    namespace: asm-ingress
    resources:
    - ../base
    - role.yaml
    - rolebinding.yaml
    patches:
    - path: service-proto-type.yaml
      target:
        kind: Service
    - path: gateway.yaml
      target:
        kind: Gateway
    EOF
    
  6. Appliquez la configuration de la passerelle d'entrée aux deux clusters :

    kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant
    kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
    

Exposer les pods de passerelle d'entrée à l'équilibreur de charge à l'aide d'un service multicluster

Dans cette section, vous exportez les pods de la passerelle d'entrée via une ressource personnalisée ServiceExport. Vous devez exporter les pods de la passerelle d'entrée via une ressource personnalisée ServiceExport pour les raisons suivantes :

  1. Dans Cloud Shell, activez les services multiclusters (MCS) pour le parc :

    gcloud container fleet multi-cluster-services enable
    
  2. Accordez à MCS les autorisations IAM requises pour le projet ou le parc :

    gcloud projects add-iam-policy-binding PROJECT_ID \
     --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
     --role "roles/compute.networkViewer"
    
  3. Créez le fichier YAML ServiceExport :

    cat <<EOF > ${WORKDIR}/svc_export.yaml
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    EOF
    
  4. Appliquez le fichier YAML ServiceExport aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yaml
    

    Si vous recevez le message d'erreur suivant, attendez quelques instants que les définitions de ressources personnalisées (CRD) MCS soient installées. Ensuite, exécutez à nouveau les commandes pour appliquer le fichier YAML ServiceExport aux deux clusters.

    error: resource mapping not found for name: "asm-ingressgateway" namespace: "asm-ingress" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1"
    ensure CRDs are installed first
    

Créer des ressources d'adresse IP externe, d'enregistrement DNS et de certificat TLS

Dans cette section, vous allez créer des ressources réseau compatibles avec les ressources d'équilibrage de charge que vous créerez plus loin dans ce déploiement.

  1. Dans Cloud Shell, réservez une adresse IP externe statique :

    gcloud compute addresses create mcg-ip --global
    

    Une adresse IP statique est utilisée par la ressource GKE Gateway. Cela permet à l'adresse IP de rester identique, même si l'équilibreur de charge externe est recréé.

  2. Obtenez l'adresse IP statique et stockez-la en tant que variable d'environnement :

    export MCG_IP=$(gcloud compute addresses describe mcg-ip --global --format "value(address)")
    echo ${MCG_IP}
    

    Pour créer un mappage stable et lisible avec votre adresse IP Gateway, vous devez disposer d'un enregistrement DNS public.

    Vous pouvez utiliser le fournisseur DNS de votre choix et l'automatisation de votre choix. Ce déploiement utilise Endpoints au lieu de créer une zone DNS gérée. Endpoints offre un enregistrement DNS géré par Google gratuit pour une adresse IP externe.

  3. Exécutez la commande suivante pour créer un fichier YAML nommé dns-spec.yaml :

    cat <<EOF > ${WORKDIR}/dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.PROJECT_ID.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.PROJECT_ID.cloud.goog"
      target: "${MCG_IP}"
    EOF
    

    Le fichier dns-spec.yaml définit l'enregistrement DNS public sous la forme frontend.endpoints.PROJECT_ID.cloud.goog, où PROJECT_ID est votre identifiant de projet unique.

  4. Déployez le fichier dns-spec.yaml pour créer l'entrée DNS. Ce processus prend quelques minutes.

    gcloud endpoints services deploy ${WORKDIR}/dns-spec.yaml
    
  5. Créez un certificat à l'aide du gestionnaire de certificats pour le nom d'entrée DNS que vous avez créé à l'étape précédente :

    gcloud certificate-manager certificates create mcg-cert \
        --domains="frontend.endpoints.PROJECT_ID.cloud.goog"
    

    Un certificat TLS géré par Google permet d'interrompre les requêtes client entrantes au niveau de l'équilibreur de charge.

  6. Créer un mappage de certificat

    gcloud certificate-manager maps create mcg-cert-map
    

    L'équilibreur de charge référence le certificat via l'entrée de mappage de certificat que vous allez créer à l'étape suivante.

  7. Créez une entrée de mappage de certificat pour le certificat que vous avez créé précédemment dans cette section :

    gcloud certificate-manager maps entries create mcg-cert-map-entry \
        --map="mcg-cert-map" \
        --certificates="mcg-cert" \
        --hostname="frontend.endpoints.PROJECT_ID.cloud.goog"
    

Créez des stratégies de service de backend et des ressources d'équilibreur de charge

Dans cette section, vous allez effectuer les tâches suivantes :

  • Créer une stratégie de sécurité Google Cloud Armor avec des règles.
  • Créer une règle qui permet à l'équilibreur de charge de vérifier la réactivité des pods de la passerelle d'entrée via le fichier YAML ServiceExport que vous avez créé précédemment.
  • Utiliser l'API GKE Gateway pour créer une ressource d'équilibreur de charge.
  • Utiliser la ressource personnalisée GatewayClass pour définir le type d'équilibreur de charge spécifique.
  • Activer l'équilibrage de charge multicluster pour le parc et désigner l'un des clusters comme cluster de configuration pour le parc.
  1. Dans Cloud Shell, créer une stratégie de sécurité Google Cloud Armor :

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. Créer une règle pour votre stratégie de sécurité :

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    
  3. Créez un fichier YAML pour la stratégie de sécurité et référencer le fichier YAML ServiceExport via un fichier YAML ServiceImport correspondant :

    cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml
    apiVersion: networking.gke.io/v1
    kind: GCPBackendPolicy
    metadata:
      name: cloud-armor-backendpolicy
      namespace: asm-ingress
    spec:
      default:
        securityPolicy: edge-fw-policy
      targetRef:
        group: net.gke.io
        kind: ServiceImport
        name: asm-ingressgateway
    EOF
    
  4. Appliquez la stratégie Google Cloud Armor aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    
  5. Créez un fichier YAML personnalisé qui permet à l'équilibreur de charge d'effectuer des vérifications d'état par rapport au point de terminaison d'état Envoy (port 15021 sur le chemin /healthz/ready) des pods de passerelle d'entrée dans les deux clusters :

    cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml
    apiVersion: networking.gke.io/v1
    kind: HealthCheckPolicy
    metadata:
      name: ingress-gateway-healthcheck
      namespace: asm-ingress
    spec:
      default:
        config:
          httpHealthCheck:
            port: 15021
            portSpecification: USE_FIXED_PORT
            requestPath: /healthz/ready
          type: HTTP
      targetRef:
        group: net.gke.io
        kind: ServiceImport
        name: asm-ingressgateway
    EOF
    
  6. Appliquez le fichier YAML personnalisé que vous avez créé à l'étape précédente aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    
  7. Activez l'équilibrage de charge multicluster pour le parc et désignez CLUSTER_1_NAME comme cluster de configuration :

    gcloud container fleet ingress enable \
      --config-membership=${CLUSTER_1_NAME} \
      --location=${CLUSTER_1_REGION}
    
  8. Accordez des autorisations IAM pour le contrôleur Gateway dans le parc :

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \
        --role "roles/container.admin"
    
  9. Créez le fichier YAML de l'équilibreur de charge via une ressource personnalisée Gateway qui fait référence à gke-l7-global-external-managed-mc gatewayClass et à l'adresse IP statique que vous avez créée précédemment :

    cat <<EOF > ${WORKDIR}/frontend-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      namespace: asm-ingress
      annotations:
        networking.gke.io/certmap: mcg-cert-map
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http # list the port only so we can redirect any incoming http requests to https
        protocol: HTTP
        port: 80
      - name: https
        protocol: HTTPS
        port: 443
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
      addresses:
      - type: NamedAddress
        value: mcg-ip
    EOF
    
  10. Appliquez le fichier YAML frontend-gateway aux deux clusters. Seul CLUSTER_1_NAME fait autorité, sauf si vous désignez un autre cluster de configuration comme faisant autorité :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
    
  11. Créez un fichier YAML HTTPRoute appelé default-httproute.yaml qui indique à la ressource Gateway d'envoyer des requêtes aux passerelles d'entrée :

    cat << EOF > ${WORKDIR}/default-httproute.yaml
    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: default-httproute
      namespace: asm-ingress
    spec:
      parentRefs:
      - name: external-http
        namespace: asm-ingress
        sectionName: https
      rules:
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
          port: 443
    EOF
    
  12. Appliquez le fichier YAML HTTPRoute que vous avez créé à l'étape précédente aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
    
  13. Pour effectuer des redirections HTTP vers HTTP(S), créez un fichier YAML HTTPRoute supplémentaire appelé default-httproute-redirect.yaml :

    cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: http-to-https-redirect-httproute
      namespace: asm-ingress
    spec:
      parentRefs:
      - name: external-http
        namespace: asm-ingress
        sectionName: http
      rules:
      - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
    EOF
    
  14. Appliquez le fichier YAML de redirection HTTPRoute aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
    
  15. Inspectez la ressource Gateway pour vérifier la progression du déploiement de l'équilibreur de charge :

    kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n asm-ingress
    

    Le résultat affiche les informations que vous avez saisies dans cette section.

Déployer l'exemple d'application "whereami"

Ce guide utilise whereami comme exemple d'application pour indiquer directement les clusters qui répondent aux requêtes. La section suivante configure deux déploiements distincts sur les deux clusters : un déploiement frontend et un déploiement backend.

Le déploiement frontend est la première charge de travail à recevoir la requête. Il appelle ensuite le déploiement backend.

Ce modèle permet de démontrer une architecture d'applications multiservices. Les services frontend et backend sont déployés sur les deux clusters.

  1. Dans Cloud Shell, créez les espaces de noms pour un frontend et un backend whereami sur les deux clusters, puis activez l'injection d'espaces de noms :

    kubectl --context=${CLUSTER_1_NAME} create ns frontend
    kubectl --context=${CLUSTER_1_NAME} label namespace frontend istio-injection=enabled
    kubectl --context=${CLUSTER_1_NAME} create ns backend
    kubectl --context=${CLUSTER_1_NAME} label namespace backend istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} create ns frontend
    kubectl --context=${CLUSTER_2_NAME} label namespace frontend istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} create ns backend
    kubectl --context=${CLUSTER_2_NAME} label namespace backend istio-injection=enabled
    
  2. Créez une variante kustomize pour le backend whereami :

    mkdir -p ${WORKDIR}/whereami-backend/base
    
    cat <<EOF > ${WORKDIR}/whereami-backend/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
    EOF
    
    mkdir ${WORKDIR}/whereami-backend/variant
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/cm-flag.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: whereami
    data:
      BACKEND_ENABLED: "False" # assuming you don't want a chain of backend calls
      METADATA:        "backend"
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/service-type.yaml
    apiVersion: "v1"
    kind: "Service"
    metadata:
      name: "whereami"
    spec:
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/kustomization.yaml
    nameSuffix: "-backend"
    namespace: backend
    commonLabels:
      app: whereami-backend
    resources:
    - ../base
    patches:
    - path: cm-flag.yaml
      target:
        kind: ConfigMap
    - path: service-type.yaml
      target:
        kind: Service
    EOF
    
  3. Appliquez la variante backend whereami aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-backend/variant
    kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-backend/variant
    
  4. Créez une variante kustomize pour le frontend whereami :

    mkdir -p ${WORKDIR}/whereami-frontend/base
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
    EOF
    
    mkdir whereami-frontend/variant
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/cm-flag.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: whereami
    data:
      BACKEND_ENABLED: "True"
      BACKEND_SERVICE: "http://whereami-backend.backend.svc.cluster.local"
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/service-type.yaml
    apiVersion: "v1"
    kind: "Service"
    metadata:
      name: "whereami"
    spec:
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/kustomization.yaml
    nameSuffix: "-frontend"
    namespace: frontend
    commonLabels:
      app: whereami-frontend
    resources:
    - ../base
    patches:
     path: cm-flag.yaml
      target:
        kind: ConfigMap
    - path: service-type.yaml
      target:
        kind: Service
    EOF
    
  5. Appliquez la variante frontend whereami aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
    kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
    
  6. Créez un fichier YAML VirtualService pour acheminer les requêtes vers le frontend whereami :

    cat << EOF > ${WORKDIR}/frontend-vs.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: whereami-vs
      namespace: frontend
    spec:
      gateways:
      - asm-ingress/asm-ingressgateway
      hosts:
      - 'frontend.endpoints.PROJECT_ID.cloud.goog'
      http:
      - route:
        - destination:
            host: whereami-frontend
            port:
              number: 80
    EOF
    
  7. Appliquez le fichier YAML frontend-vs aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
    
  8. Maintenant que vous avez déployé frontend-vs.yaml sur les deux clusters, essayez d'appeler le point de terminaison public de vos clusters :

    curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
    

    Le résultat ressemble à ce qui suit :

    {
      "backend_result": {
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "8396338201253702608",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "whereami-backend.backend.svc.cluster.local",
        "metadata": "backend",
        "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-645h",
        "pod_ip": "10.124.0.199",
        "pod_name": "whereami-backend-7cbdfd788-8mmnq",
        "pod_name_emoji": "📸",
        "pod_namespace": "backend",
        "pod_service_account": "whereami-backend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T03:46:24",
        "zone": "us-east4-b"
      },
      "cluster_name": "edge-to-mesh-01",
      "gce_instance_id": "1047264075324910451",
      "gce_service_account": "e2m-mcg-01.svc.id.goog",
      "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
      "metadata": "frontend",
      "node_name": "gk3-edge-to-mesh-01-pool-2-d687e3c0-5kf2",
      "pod_ip": "10.54.1.71",
      "pod_name": "whereami-frontend-69c4c867cb-dgg8t",
      "pod_name_emoji": "🪴",
      "pod_namespace": "frontend",
      "pod_service_account": "whereami-frontend",
      "project_id": "e2m-mcg-01",
      "timestamp": "2023-12-01T03:46:24",
      "zone": "us-central1-c"
    }
    

Si vous exécutez la commande curl plusieurs fois, vous verrez que les réponses (de frontend et de backend) proviennent de différentes régions. Dans sa réponse, l'équilibreur de charge fournit un routage géographique. Cela signifie que l'équilibreur de charge achemine les requêtes du client vers le cluster actif le plus proche, mais que les requêtes arrivent toujours de manière aléatoire. Lorsque les requêtes passent occasionnellement d'une région à une autre, cela augmente la latence et les coûts.

Dans la section suivante, vous allez mettre en œuvre l'équilibrage de charge de la zone dans le maillage de services pour conserver les requêtes en local.

Activer et tester l'équilibrage de charge de la localité pour whereami

Dans cette section, vous allez mettre en œuvre l'équilibrage de charge de la zone dans le maillage de services pour conserver les requêtes en local. Vous allez également effectuer des tests pour voir comment il gère différents scénarios de défaillance.

Lorsque vous envoyez une requête au service frontend whereami, l'équilibreur de charge envoie la requête au cluster ayant la latence la plus faible par rapport au client. Cela signifie que les pods de passerelle d'entrée du réseau maillé équilibrent la charge des requêtes vers les pods frontend whereami sur les deux clusters. Cette section résout ce problème en activant l'équilibrage de charge de la zone dans le maillage.

  1. Dans Cloud Shell, créez un fichier YAML DestinationRule qui active le basculement régional d'équilibrage de charge de la zone vers le service frontend :

    cat << EOF > ${WORKDIR}/frontend-dr.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: frontend
      namespace: frontend
    spec:
      host: whereami-frontend.frontend.svc.cluster.local
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 0
        loadBalancer:
          simple: LEAST_REQUEST
          localityLbSetting:
            enabled: true
        outlierDetection:
          consecutive5xxErrors: 1
          interval: 1s
          baseEjectionTime: 1m
    EOF
    

    L'exemple de code précédent n'active que le routage local pour le service frontend. Vous avez également besoin d'une configuration supplémentaire qui gère le backend.

  2. Appliquez le fichier YAML frontend-dr aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
    
  3. Créez un fichier YAML DestinationRule qui active le basculement régional d'équilibrage de charge de la zone vers le service backend :

    cat << EOF > ${WORKDIR}/backend-dr.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
    n    ame: backend
      namespace: backend
    spec:
      host: whereami-backend.backend.svc.cluster.local
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 0
        loadBalancer:
          simple: LEAST_REQUEST
          localityLbSetting:
            enabled: true
        outlierDetection:
          consecutive5xxErrors: 1
          interval: 1s
          baseEjectionTime: 1m
    EOF
    
  4. Appliquez le fichier YAML backend-dr aux deux clusters :

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yaml
    

    Avec les deux ensembles de fichiers YAML DestinationRule appliqués aux deux clusters, les requêtes restent locales au cluster vers lequel elles sont acheminées.

    Pour tester le basculement du service frontend, réduisez le nombre d'instances répliquées de la passerelle d'entrée dans votre cluster principal.

    Du point de vue de l'équilibreur de charge multirégional, cette action simule une défaillance de cluster. Cela entraîne l'échec des vérifications d'état de l'équilibreur de charge pour ce cluster. Cet exemple utilise le cluster dans CLUSTER_1_REGION. Vous ne devriez voir que les réponses du cluster dans CLUSTER_2_REGION.

  5. Réduisez à zéro le nombre d'instances répliquées de la passerelle d'entrée de votre cluster principal, puis appelez le point de terminaison public pour vérifier que les requêtes ont basculé vers l'autre cluster :

    kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=0 deployment/asm-ingressgateway
    

    La sortie doit ressembler à ceci :

    $ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
    {
      "backend_result": {
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "2717459599837162415",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "whereami-backend.backend.svc.cluster.local",
        "metadata": "backend",
        "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2",
        "pod_ip": "10.124.1.7",
        "pod_name": "whereami-backend-7cbdfd788-mp8zv",
        "pod_name_emoji": "🏌🏽‍♀",
        "pod_namespace": "backend",
        "pod_service_account": "whereami-backend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T05:41:18",
        "zone": "us-east4-b"
      },
      "cluster_name": "edge-to-mesh-02",
      "gce_instance_id": "6983018919754001204",
      "gce_service_account": "e2m-mcg-01.svc.id.goog",
      "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
      "metadata": "frontend",
      "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn",
      "pod_ip": "10.124.1.142",
      "pod_name": "whereami-frontend-69c4c867cb-xf8db",
      "pod_name_emoji": "🏴",
      "pod_namespace": "frontend",
      "pod_service_account": "whereami-frontend",
      "project_id": "e2m-mcg-01",
      "timestamp": "2023-12-01T05:41:18",
      "zone": "us-east4-b"
    }
    
  6. Pour reprendre le routage du trafic standard, restaurez les instances répliquées de la passerelle d'entrée à la valeur d'origine dans le cluster :

    kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=3 deployment/asm-ingressgateway
    
  7. Simulez une défaillance du service backend en réduisant le nombre d'instances répliquées dans la région principale à 0 :

    kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backend
    

    Vérifiez que les réponses du service frontend proviennent de la région principale us-central1 via l'équilibreur de charge et que les réponses du service backend proviennent de la région secondaire us-east4.

    Le résultat doit également inclure une réponse pour le service frontend de la région principale (us-central1) et une réponse pour le service backend de la région secondaire (us-east4), comme prévu.

  8. Restaurez les instances répliquées du service de backend à leur valeur d'origine pour reprendre le routage du trafic classique :

    kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
    

Vous disposez maintenant d'un équilibreur de charge HTTP(S) global servant d'interface à votre application multirégionale hébergée par le maillage de services.

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans le cadre de ce déploiement soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer le projet

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Supprimer les ressources individuelles

Si vous souhaitez conserver le projet Google Cloud que vous avez utilisé dans ce déploiement, supprimez les différentes ressources.

  1. Dans Cloud Shell, supprimez les ressources HTTPRoute :

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
    
  2. Supprimez les ressources GKE Gateway :

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
    
  3. Supprimez les règles :

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    
  4. Supprimez les exportations de service :

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
    
  5. Supprimez les ressources Google Cloud Armor :

    gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet
    gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
    
  6. Supprimez les ressources du gestionnaire de certificats :

    gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet
    gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet
    gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
    
  7. Supprimez l'entrée Endpoints DNS :

    gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
    
  8. Supprimez l'adresse IP statique :

    gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
    
  9. Supprimez les clusters GKE Autopilot. Cette étape prend plusieurs minutes.

    gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} --quiet
    gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} --quiet
    

Étape suivante

Contributeurs

Auteurs :

Autres contributeurs :