Extensibilité du plan de données avec EnvoyFilter

Vous pouvez utiliser l'API EnvoyFilter pour étendre les capacités du plan de données dans Cloud Service Mesh, ce qui n'est pas possible avec d'autres API Istio. L'API EnvoyFilter vous permet de personnaliser la configuration Envoy générée à partir d'autres règles appliquées aux charges de travail, par exemple en ajoutant des filtres à la chaîne de filtres HTTP.

Remarques importantes

  • Notez que la surface de l'API est liée aux détails d'implémentation internes. Vous devez donc faire particulièrement attention lorsque vous utilisez cette fonctionnalité, car des configurations incorrectes pourraient déstabiliser le maillage. N'utilisez l'API EnvoyFilter que si les autres API Istio ne répondent pas à vos besoins.
  • L'API EnvoyFilter est compatible avec des restrictions spécifiques sur les champs et les extensions qui peuvent être utilisés à des fins de fiabilité et de compatibilité. Pour obtenir la liste exhaustive des fonctionnalités compatibles avec l'API EnvoyFilter, consultez Fonctionnalités compatibles avec les API Istio (plan de contrôle géré).
  • L'assistance proposée par Google se limite à la propagation de la configuration fournie par l'utilisateur aux charges de travail avec des sidecars Envoy. Elle ne s'étend pas à l'exactitude de la configuration spécifiée à l'aide des API par extension.

Champs d'API compatibles

L'API EnvoyFilter est compatible avec l'implémentation du plan de contrôle TRAFFIC_DIRECTOR uniquement avec une compatibilité limitée, comme suit :

  • targetRefs : non compatible
  • configPatches[].applyTo : seule la valeur HTTP_FILTER est acceptée
  • configPatches[].patch.operation : seuls INSERT_FIRST et INSERT_BEFORE sont acceptés lorsqu'ils sont utilisés avec le filtre de route.
  • configPatches[].patch.value.type_url : consultez Extensions compatibles.
  • configPatches[].patch.filterClass : non compatible
  • configPatches[].match.proxy : non compatible
  • configPatches[].match.routeConfiguration : non compatible
  • configPatches[].match.cluster : non compatible
  • Les champs suivants ne sont acceptés que pour l'opération INSERT_BEFORE :
    • configPatches[].match.listener : seule filter est acceptée.
    • configPatches[].match.listener.filter.name : seule envoy.filters.network.http_connection_manager est acceptée.
    • configPatches[].match.listener.filter.subFilter.name : seule envoy.filters.http.router est acceptée.

Extensions acceptées

Vous trouverez ci-dessous la liste des extensions compatibles, ainsi que les champs d'API compatibles pour les différents canaux de diffusion. La définition de l'API et sa sémantique sont disponibles dans la documentation officielle d'Envoy.

type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit

Champ Rapide Standard Stable
stat_prefix
status
token_bucket
filter_enabled
filter_enforced
response_headers_to_add
request_headers_to_add_when_not_enforced
local_rate_limit_per_downstream_connection
enable_x_ratelimit_headers

type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb

Champ Rapide Standard Stable
(Aucun champ)

type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor

Champ Rapide Standard Stable
compressor_library
choose_first
response_direction_config.common_config.min_content_length
response_direction_config.common_config.content_type
response_direction_config.common_config.enabled
response_direction_config.disable_on_etag_header
response_direction_config.remove_accept_encoding_header
response_direction_config.uncompressible_response_codes
request_direction_config.common_config.min_content_length
request_direction_config.common_config.content_type
request_direction_config.common_config.enabled

Pour savoir comment mettre à jour la configuration de votre compresseur EnvoyFilter afin qu'elle soit entièrement compatible, consultez Moderniser les configurations de compresseur EnvoyFilter.

type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua

Champ Rapide Standard Stable
stat_prefix
default_source_code.inline_string

† Points importants et restrictions concernant les scripts Lua intégrés :

  • Pour garantir la sécurité et la stabilité, seule une partie des fonctionnalités Lua et des wrappers Envoy Lua est autorisée. Si vous utilisez des fonctionnalités non compatibles ou dépassez les limites documentées, l'EnvoyFilter sera refusé.
  • Les scripts Lua complexes peuvent avoir un impact sur les performances. Testez minutieusement l'utilisation des ressources par vos scripts.

Fonctionnalités Lua non compatibles :
Les fonctionnalités Lua et les wrappers Lua fournis par Envoy suivants ne sont pas compatibles :

  • Wrappers Envoy :
    • httpCall
    • filterContext
  • Bibliothèque standard Lua :
    • Package de base : collectgarbage, dofile, getmetatable, loadfile, rawset, setfenv, setmetatable
    • Modules : module
    • Package OS : execute, remove, rename, setlocale
    • Bibliothèques d'E/S et de débogage : io, debug
  • Extensions LuaJIT : ffi, jit

Limites de taille et de nombre de scripts :

  • Taille d'un script individuel : un script Lua intégré fourni dans default_source_code.inline_string ne peut pas dépasser 50 Ko.
  • Taille totale du script : la taille totale de tous les scripts Lua dans toutes les ressources EnvoyFilter d'un même cluster ne doit pas dépasser 100 Ko.
  • Nombre de correctifs : le nombre total de configPatches Lua EnvoyFilter dans toutes les ressources EnvoyFilter d'un même cluster est limité à 10.

Exemple d'utilisation

Dans ce tutoriel, vous allez apprendre à utiliser la limitation du débit local intégrée d'Envoy pour limiter dynamiquement le trafic vers un service à l'aide de l'API EnvoyFilter.

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud :

Une fois que vous aurez terminé ce tutoriel, évitez de 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

Déployer une passerelle d'entrée

  1. Définissez le contexte actuel de kubectl sur le cluster :

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Créez un espace de noms pour votre passerelle d'entrée :

    kubectl create namespace asm-ingress
    
  3. Activez l'espace de noms pour l'injection : Les étapes dépendent de votre mise en œuvre du plan de contrôle.

    Appliquez les étiquettes d'injection par défaut à l'espace de noms.

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    
  4. Déployez l'exemple de passerelle dans le dépôt anthos-service-mesh-samples :

    kubectl apply -n asm-ingress \
        -f docs/shared/asm-ingress-gateway
    

    Résultat attendu :

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

Déployez l'exemple d'application Boutique en ligne.

  1. Si ce n'est pas le cas, définissez le contexte actuel de kubectl sur le cluster :

    gcloud container clusters get-credentials CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    
  2. Créez l'espace de noms pour l'exemple d'application :

    kubectl create namespace onlineboutique
    
  3. Ajoutez un libellé à l'espace de noms onlineboutique pour injecter automatiquement les proxys Envoy :

    kubectl label namespace onlineboutique \
       istio.io/rev- istio-injection=enabled --overwrite
    
  4. Déployez l'application exemple, le VirtualService pour l'interface et les comptes de service pour les charges de travail. Dans ce tutoriel, vous allez déployer Online Boutique, une application de démonstration de microservices.

    kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
    
    kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

Afficher vos services

  1. Affichez les pods dans l'espace de noms onlineboutique :

    kubectl get pods -n onlineboutique
    

    Résultat attendu :

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    Tous les pods de votre application doivent être opérationnels, avec une valeur 2/2 dans la colonne READY. Cela indique que les pods ont un proxy side-car Envoy injecté avec succès. Si 2/2 ne s'affiche pas au bout de quelques minutes, consultez le guide de dépannage.

  2. Obtenez l'adresse IP externe et définissez-la sur une variable :

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

    Vous obtenez un résultat semblable à celui-ci :

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. Accédez à l'adresse EXTERNAL-IP dans votre navigateur Web. La boutique en ligne devrait s'afficher dans votre navigateur.

    Interface de la boutique en ligne

Appliquer la configuration de la limite de débit

Cette section applique une ressource EnvoyFilter pour limiter tout le trafic vers le service frontend à cinq requêtes par minute.

  1. Appliquez le CR au service frontend :

    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    metadata:
      name: frontend-local-ratelimit
      namespace: onlineboutique
    spec:
      workloadSelector:
        labels:
          app: frontend
      configPatches:
        - applyTo: HTTP_FILTER
          match:
            context: SIDECAR_INBOUND
            listener:
              filterChain:
                filter:
                  name: "envoy.filters.network.http_connection_manager"
                  subFilter:
                    name: "envoy.filters.http.router"
          patch:
            operation: INSERT_BEFORE
            value:
              name: envoy.filters.http.local_ratelimit
              typed_config:
                "@type": type.googleapis.com/udpa.type.v1.TypedStruct
                type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
                value:
                  stat_prefix: http_local_rate_limiter
                  token_bucket:
                    max_tokens: 5
                    tokens_per_fill: 5
                    fill_interval: 60s
                  filter_enabled:
                    runtime_key: local_rate_limit_enabled
                    default_value:
                      numerator: 100
                      denominator: HUNDRED
                  filter_enforced:
                    runtime_key: local_rate_limit_enforced
                    default_value:
                      numerator: 100
                      denominator: HUNDRED
    EOF
    

    Résultat attendu :

    envoyfilter.networking.istio.io/frontend-local-ratelimit created
    
  2. Vérifiez que l'état du CR ne signale aucune erreur :

    kubectl get envoyfilter -n onlineboutique frontend-local-ratelimit -o yaml
    

    Résultat attendu :

    ...
    status:
      conditions:
      - lastTransitionTime: "2025-06-30T14:29:25.467017594Z"
        message: This resource has been accepted. This does not mean it has been propagated
          to all proxies yet
        reason: Accepted
        status: "True"
        type: Accepted
    
  3. Supprimez le déploiement loadgenerator, car il appelle le service plusieurs fois, ce qui consomme des jetons :

    kubectl delete -n onlineboutique deployment loadgenerator
    

    Résultat attendu :

    deployment.apps/loadgenerator deleted
    
  4. À l'aide de curl, vérifiez qu'au maximum cinq requêtes sont autorisées en 60 secondes. Le code 429 indique que la limitation du débit est appliquée.

    for i in {1..10}; do curl -s http://${FRONTEND_IP} -o /dev/null -w "%{http_code}\n"; sleep 1; done
    

    Résultat attendu :

    200
    200
    200
    200
    200
    429
    429
    429
    429
    429
    

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans ce tutoriel continuent d'être facturées sur votre compte Google Cloud , vous pouvez supprimer le projet ou supprimer les ressources individuelles.

Supprimer le projet

Dans Cloud Shell, supprimez le projet :

  gcloud projects delete PROJECT_ID

Supprimer les ressources

  • Si vous souhaitez conserver votre cluster et supprimer l'exemple de boutique en ligne, procédez comme suit :

    1. Supprimez les espaces de noms de l'application :

      kubectl delete namespace onlineboutique
      

      Résultat attendu :

      namespace "onlineboutique" deleted
      
    2. Supprimez l'espace de noms de la passerelle d'entrée :

      kubectl delete namespace asm-ingress
      

      Résultat attendu :

      namespace "asm-ingress" deleted
      
  • Si vous souhaitez éviter des frais supplémentaires, supprimez le cluster :

    gcloud container clusters delete CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    

Dépannage

Consultez Résoudre les problèmes d'extensibilité du plan de données.