EnvoyFilter를 사용한 데이터 영역 확장성

EnvoyFilter API를 사용하여 다른 Istio API를 사용하는 것으로는 달성할 수 없는 Cloud Service Mesh의 데이터 영역 기능을 확장할 수 있습니다. EnvoyFilter API를 사용하면 워크로드에 적용된 다른 정책에서 생성된 Envoy 구성을 맞춤설정할 수 있습니다(예: HTTP 필터 체인에 필터 추가).

중요 고려사항

  • API 노출 영역은 내부 구현 세부정보와 연결되어 있으므로 잘못된 구성으로 인해 메시가 불안정해질 수 있으므로 이 기능을 사용할 때는 특별히 주의해야 합니다. 다른 Istio API가 요구사항에 맞지 않는 경우에만 EnvoyFilter API를 사용하세요.
  • EnvoyFilter API는 안정성과 지원 가능성을 위해 사용할 수 있는 필드와 확장 프로그램에 관한 특정 제한사항과 함께 지원됩니다. EnvoyFilter API에서 지원되는 기능의 전체 목록은 Istio API를 사용하는 지원 기능 (관리형 컨트롤 플레인)을 참고하세요.
  • Google에서 제공하는 지원 범위는 Envoy 사이드카가 있는 워크로드에 사용자가 제공한 구성을 전파하는 데 국한되며 확장 프로그램별 API를 사용하여 지정된 구성의 정확성에는 적용되지 않습니다.

지원되는 API 필드

EnvoyFilter API는 TRAFFIC_DIRECTOR 컨트롤 플레인 구현에서만 지원되며 다음과 같이 제한된 지원만 제공됩니다.

  • targetRefs: 지원되지 않음
  • configPatches[].applyTo : HTTP_FILTER만 지원됩니다.
  • configPatches[].patch.operation: 경로 필터와 함께 사용되는 경우 INSERT_FIRSTINSERT_BEFORE만 지원됩니다.
  • configPatches[].patch.value.type_url: 지원되는 확장 프로그램 참고
  • configPatches[].patch.filterClass: 지원되지 않음
  • configPatches[].match.proxy: 지원되지 않음
  • configPatches[].match.routeConfiguration: 지원되지 않음
  • configPatches[].match.cluster: 지원되지 않음
  • 다음 필드는 INSERT_BEFORE 작업에만 지원됩니다.
    • configPatches[].match.listener: filter만 지원됩니다.
    • configPatches[].match.listener.filter.name: envoy.filters.network.http_connection_manager만 지원됩니다.
    • configPatches[].match.listener.filter.subFilter.name: envoy.filters.http.router만 지원됩니다.

지원되는 확장 프로그램

다음은 다양한 출시 채널에서 지원되는 API 필드와 함께 지원되는 확장 프로그램 목록입니다. API 정의와 의미 체계는 공식 Envoy 문서에서 확인할 수 있습니다.

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

필드 신속 일반 정식
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

필드 신속 일반 정식
(필드 없음)

사용 예시

이 튜토리얼에서는 Envoy의 기본 제공 로컬 비율 제한을 사용하여 EnvoyFilter API를 통해 서비스 트래픽을 동적으로 제한하는 방법을 알아봅니다.

비용

이 튜토리얼에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud구성요소를 사용합니다.

이 튜토리얼을 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않도록 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

인그레스 게이트웨이 배포

  1. kubectl의 현재 컨텍스트를 클러스터로 설정합니다.

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. 인그레스 게이트웨이에 대해 네임스페이스를 만듭니다.

    kubectl create namespace asm-ingress
    
  3. 네임스페이스의 삽입을 사용 설정합니다. 이 단계는 컨트롤 플레인 구현에 따라 다릅니다.

    기본 삽입 라벨을 네임스페이스에 적용합니다.

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    
  4. anthos-service-mesh-samples 저장소에 게이트웨이 예시를 배포합니다.

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

    예상 출력:

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

Online Boutique 샘플 애플리케이션 배포

  1. 아직 설정하지 않은 경우 kubectl의 현재 컨텍스트를 클러스터로 설정합니다.

    gcloud container clusters get-credentials CLUSTER_NAME  \
      --project=PROJECT_ID \
      --zone=CLUSTER_LOCATION 
    
  2. 샘플 애플리케이션의 네임스페이스를 만듭니다.

    kubectl create namespace onlineboutique
    
  3. Envoy 프록시를 자동으로 주입하도록 onlineboutique 네임스페이스에 라벨을 지정합니다.

    kubectl label namespace onlineboutique \
       istio.io/rev- istio-injection=enabled --overwrite
    
  4. 샘플 앱, 프런트엔드용 VirtualService, 워크로드의 서비스 계정을 배포합니다. 이 튜토리얼에서는 마이크로서비스 데모 앱인 Online Boutique를 배포합니다.

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

서비스 보기

  1. onlineboutique 네임스페이스의 포드를 확인합니다.

    kubectl get pods -n onlineboutique
    

    예상 출력:

    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
    

    애플리케이션의 모든 포드가 작동되고 READY 열의 2/2를 사용해서 실행됩니다. 이것은 포드에 Envoy 사이드카 프록시가 성공적으로 주입된 것을 나타냅니다. 몇 분 후에도 2/2가 표시되지 않는다면 문제 해결 가이드를 방문하세요.

  2. 외부 IP를 가져오고 이를 변수로 설정합니다.

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

    다음과 비슷한 출력이 표시됩니다.

    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. 웹브라우저에서 EXTERNAL-IP 주소를 방문합니다. 브라우저에 Online Boutique 매장이 표시될 것으로 예상됩니다.

    Online Boutique 프런트엔드

비율 제한 구성 적용

이 섹션에서는 EnvoyFilter 리소스를 적용하여 frontend 서비스에 대한 모든 트래픽을 5req/min으로 제한합니다.

  1. frontend 서비스에 CR을 적용합니다.

    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
    

    예상 출력:

    envoyfilter.networking.istio.io/frontend-local-ratelimit created
    
  2. CR 상태에 오류가 보고되지 않는지 확인합니다.

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

    예상 출력:

    ...
    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. 토큰을 소비하는 서비스를 여러 번 호출하므로 loadgenerator 배포를 삭제합니다.

    kubectl delete -n onlineboutique deployment loadgenerator
    

    예상 출력:

    deployment.apps/loadgenerator deleted
    
  4. curl를 사용하여 60초 동안 5개 이하의 요청이 허용되는지 확인합니다. 429 코드는 비율 제한이 적용되고 있음을 나타냅니다.

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

    예상 출력:

    200
    200
    200
    200
    200
    429
    429
    429
    429
    429
    

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 프로젝트를 삭제하거나 개별 리소스를 삭제하면 됩니다.

프로젝트 삭제

Cloud Shell에서 프로젝트를 삭제합니다.

  gcloud projects delete PROJECT_ID

리소스 삭제

  • 클러스터를 유지하고 Online Boutique를 삭제하려면 다음 안내를 따르세요.

    1. 애플리케이션 네임스페이스를 삭제합니다.

      kubectl delete namespace onlineboutique
      

      예상 출력:

      namespace "onlineboutique" deleted
      
    2. 인그레스 게이트웨이 네임스페이스를 삭제합니다.

      kubectl delete namespace asm-ingress
      

      예상 출력:

      namespace "asm-ingress" deleted
      
  • 추가 요금이 청구되지 않도록 하려면 클러스터를 삭제하세요.

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

문제 해결

데이터 영역 확장성 문제 해결을 참고하세요.