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 lo contrario, no se pueden lograr con otras APIs de Istio. Con la API de EnvoyFilter, puedes personalizar la configuración de Envoy generada 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 los detalles de implementación internos, por lo que se debe tener especial cuidado cuando se usa esta función, ya que las configuraciones incorrectas podrían desestabilizar la malla. Usa la API de EnvoyFilter solo si otras APIs de Istio no satisfacen tus necesidades.
  • La API de EnvoyFilter es compatible con restricciones específicas sobre qué campos y extensiones se pueden usar para la confiabilidad y la compatibilidad. 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 compatibilidad que ofrece Google se limita a propagar la configuración proporcionada por el usuario a las cargas de trabajo con archivos adicionales de Envoy y no se extiende a la exactitud de la configuración especificada con las APIs por extensión.

Campos de API compatibles

La API de EnvoyFilter es compatible con la implementación del plano de control 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 compatibles
  • configPatches[].patch.filterClass: No compatible
  • configPatches[].match.proxy: No compatible
  • configPatches[].match.routeConfiguration: No compatible
  • configPatches[].match.cluster: No compatible
  • Los siguientes campos solo son compatibles con 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 muestra la lista de extensiones compatibles junto con sus campos de API compatibles en varios 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)

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 completes el instructivo puedes borrar los recursos que hayas creado 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 la 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 aún 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 muestra:

    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, el 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
    

Consulta tus servicios

  1. Consulta 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 muestra 2/2 después de un par de minutos, visita 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 por minuto.

  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 de 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 segundos. El código 429 indica que se aplica el 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
    

Limpia

Para evitar que se apliquen cargos continuos a tu Google Cloud cuenta por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra 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 la puerta de enlace de entrada:

      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.