Extensibilidad del plano de datos con EnvoyFilter

Puedes usar la API de EnvoyFilter para extender las capacidades del plano de datos en Cloud Service Mesh que, de otro modo, no se pueden lograr con otras APIs de Istio. Con la API de EnvoyFilter, puedes personalizar la configuración de Envoy que se genera a partir de otras políticas aplicadas a las cargas de trabajo, como agregar filtros a la cadena de filtros HTTP.

Consideraciones importantes

  • Ten en cuenta que la superficie de la API está vinculada a detalles internos de la implementación, por lo que se debe tener especial cuidado al usar esta función, ya que las configuraciones incorrectas podrían desestabilizar la malla. Solo usa la API de EnvoyFilter si otras APIs de Istio no satisfacen tus necesidades.
  • La API de EnvoyFilter se admite con restricciones específicas sobre qué campos y extensiones se pueden usar para fines de confiabilidad y asistencia. Para obtener una lista exhaustiva de las funciones compatibles con la API de EnvoyFilter, consulta Funciones compatibles con las APIs de Istio (plano de control administrado).
  • El alcance de la asistencia que ofrece Google se limita a propagar la configuración proporcionada por el usuario a las cargas de trabajo con sidecars de Envoy y no se extiende a la corrección de la configuración especificada con las APIs por extensión.

Campos de la API compatibles

La API de EnvoyFilter se admite con la implementación del plano de control de TRAFFIC_DIRECTOR solo con compatibilidad limitada de la siguiente manera:

  • targetRefs: No compatible
  • configPatches[].applyTo : Solo se admite HTTP_FILTER.
  • configPatches[].patch.operation: Solo se admiten INSERT_FIRST y INSERT_BEFORE cuando se usan con el filtro de ruta.
  • configPatches[].patch.value.type_url: Consulta Extensiones admitidas
  • configPatches[].patch.filterClass: No compatible
  • configPatches[].match.proxy: No compatible
  • configPatches[].match.routeConfiguration: No compatible
  • configPatches[].match.cluster: No compatible
  • Los siguientes campos solo se admiten para la operación INSERT_BEFORE:
    • configPatches[].match.listener: Solo se admite filter.
    • configPatches[].match.listener.filter.name: Solo se admite envoy.filters.network.http_connection_manager.
    • configPatches[].match.listener.filter.subFilter.name: Solo se admite envoy.filters.http.router.

Extensiones compatibles

A continuación, se incluye la lista de extensiones admitidas junto con sus campos de API compatibles en los distintos canales de lanzamiento. La definición de la API y su semántica se pueden encontrar en la documentación oficial de Envoy.

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

Campo Rápido Normal Estable
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

Campo Rápido Normal Estable
(Sin campos)

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

Campo Rápido Normal Estable
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

Para obtener información sobre cómo actualizar la configuración del compresor EnvoyFilter para que sea totalmente compatible, consulta Moderniza las configuraciones del compresor EnvoyFilter.

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

Campo Rápido Normal Estable
stat_prefix
default_source_code.inline_string

Consideraciones y restricciones importantes para los secuencias de comandos Lua intercalados:

  • Para garantizar la seguridad y la estabilidad, solo se permite un subconjunto de funciones de Lua y wrappers de Envoy Lua. Si se usan funciones no admitidas o se superan los límites documentados, se rechazará el EnvoyFilter.
  • Las secuencias de comandos de Lua complejas pueden afectar el rendimiento. Prueba minuciosamente el uso de recursos de tus secuencias de comandos.

Funciones de Lua no admitidas:
Las siguientes funciones de Lua y los wrappers de Lua proporcionados por Envoy no son compatibles:

  • Wrappers de Envoy:
    • httpCall
    • filterContext
  • Biblioteca estándar de Lua:
    • Paquete básico: collectgarbage, dofile, getmetatable, loadfile, rawset, setfenv, setmetatable
    • Módulos: module
    • Paquete del SO: execute, remove, rename, setlocale
    • Bibliotecas de E/S y depuración: io, debug
  • Extensiones de LuaJIT: ffi, jit

Límites de tamaño y cantidad de secuencias de comandos:

  • Tamaño de secuencia de comandos individual: Una sola secuencia de comandos intercalada de Lua proporcionada en default_source_code.inline_string no puede superar los 50 KB.
  • Tamaño total del script: El tamaño total de todos los scripts de Lua en todos los recursos de EnvoyFilter dentro de un solo clúster no puede exceder los 100 KB.
  • Cantidad de parches: La cantidad total de configPatches de EnvoyFilter de Lua en todos los recursos de EnvoyFilter dentro de un solo clúster se limita a 10.

Ejemplo de uso

En este instructivo, aprenderás a usar el límite de frecuencia local integrado de Envoy para limitar de forma dinámica el tráfico a un servicio con la API de EnvoyFilter.

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Cuando finalices este instructivo, podrás borrar los recursos creados para evitar que se te sigan cobrando. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

Implementa una puerta de enlace de entrada

  1. Establece el contexto actual para kubectl en el clúster:

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Crea un espacio de nombres para tu puerta de enlace de entrada:

    kubectl create namespace asm-ingress
    
  3. Habilita el espacio de nombres para la inserción. Los pasos dependen de tu implementación del plano de control.

    Aplica la etiqueta de inserción predeterminada al espacio de nombres:

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    
  4. Implementa la puerta de enlace de ejemplo en el repositorio anthos-service-mesh-samples:

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

    Resultado esperado:

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

Implementa la aplicación de muestra de Online Boutique.

  1. Si no lo hiciste, establece el contexto actual para kubectl en el clúster:

    gcloud container clusters get-credentials CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    
  2. Crea el espacio de nombres para la aplicación de ejemplo:

    kubectl create namespace onlineboutique
    
  3. Etiqueta el espacio de nombres onlineboutique para insertar de forma automática los proxies de Envoy:

    kubectl label namespace onlineboutique \
       istio.io/rev- istio-injection=enabled --overwrite
    
  4. Implementa la app de ejemplo, VirtualService para el frontend y las cuentas de servicio para las cargas de trabajo. En este instructivo, implementarás Online Boutique, una app de demo de microservicios.

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

Cómo ver tus servicios

  1. Visualiza los Pods en el espacio de nombres onlineboutique:

    kubectl get pods -n onlineboutique
    

    Resultado esperado:

    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
    

    Todos los Pods de tu aplicación deben estar en funcionamiento, con un 2/2 en la columna READY. Esto indica que los Pods tienen un proxy de sidecar de Envoy insertado de forma correcta. Si no aparece 2/2 después de un par de minutos, consulta la Guía de solución de problemas.

  2. Obtén la IP externa y configúrala en una 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}' \
    )
    

    Verás un resultado similar al siguiente:

    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. Visita la dirección EXTERNAL-IP en tu navegador web. Deberías ver la tienda Online Boutique en tu navegador.

    Frontend de la boutique en línea

Aplica la configuración del límite de frecuencia

En esta sección, se aplica un recurso EnvoyFilter para limitar todo el tráfico al servicio frontend a 5 solicitudes/min.

  1. Aplica el CR al servicio 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
    

    Resultado esperado:

    envoyfilter.networking.istio.io/frontend-local-ratelimit created
    
  2. Verifica que el estado del CR no informe ningún error:

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

    Resultado esperado:

    ...
    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. Quita la implementación de loadgenerator, ya que llama al servicio varias veces, lo que consume tokens:

    kubectl delete -n onlineboutique deployment loadgenerator
    

    Resultado esperado:

    deployment.apps/loadgenerator deleted
    
  4. Con curl, verifica que no se permitan más de 5 solicitudes en 60 s. El código 429 indica que se está aplicando la límite de frecuencia.

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

    Resultado esperado:

    200
    200
    200
    200
    200
    429
    429
    429
    429
    429
    

Realiza una limpieza

Para evitar que se apliquen cargos continuos a tu cuenta de Google Cloud por los recursos que se usaron en este instructivo, puedes borrar el proyecto o borrar los recursos individuales.

Borra el proyecto

En Cloud Shell, borra el proyecto:

  gcloud projects delete PROJECT_ID

Borra recursos

  • Si deseas conservar el clúster y quitar la muestra de Online Retail, realiza la siguiente acción:

    1. Borra los espacios de nombres de la aplicación:

      kubectl delete namespace onlineboutique
      

      Resultado esperado:

      namespace "onlineboutique" deleted
      
    2. Borra el espacio de nombres de Ingress Gateway:

      kubectl delete namespace asm-ingress
      

      Resultado esperado:

      namespace "asm-ingress" deleted
      
  • Si deseas evitar cargos adicionales, borra el clúster:

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

Soluciona problemas

Consulta Cómo resolver problemas de extensibilidad del plano de datos.