openapi-endpoint-filter 동작 구조. API 식별자(예: /users/{id})를 request header와 Istio metric label로 삽입한다.
Introduction
아래의 openapi-endpoint-filter 에 대한 간단한 소개와 README에서 다루지 못했던 제작 동기이다.
일단 openapi-endpoint-filter 가 무엇인지는 아래의 README heading 문구가 잘 나타내는데, 부연하자면 Istio metric이 다루는 최소 단위는 workload(Deployment, StatefulSet 등) 또는 pod이기에, 실세계에서 유용한 API 단위의 metric 식별이 상당히 아쉽다. 이를 해결한다.
Rust 기반의 Proxy-Wasm 필터로, OpenAPI operation(예: GET /users/{id})을 request header에 삽입합니다. 이 header는 Istio Telemetry API를 통해 Istio 메트릭 레이블 로 매핑될 수 있으므로, 결과적으로 카디널리티 폭발 없이 엔드포인트 수준의 관찰 가능성을 확보가 가능합니다.
참고로 동일한 이슈를 다루는 Istio 공식 문서 가이드가 있지만, 이는 정규 표현식과 스캔 작업에 의존하므로 성능 문제가 발생하여 사실 상 운영 환경에서는 사용이 불가능하다. 무엇보다 OpenAPI spec을 그대로 사용하는 것이 아니기에 OpenAPI의 path template을 정규 표현식 기반으로 변환해야하기도 한다.
openapi-endpoint-filter 가 무엇을 해결하나
한마디로 표현하자면 Istio의 API 단위 관찰성 부재 이슈에 대한 해결이다.
•
Istio request.url_path의 한계: 예컨데 /users/123과 users/456 은 동일 API 호출임에도 서로 다른 API로 식별된다. 나아가 metric backend의 카디널리티 폭발 이슈로 인해 사실 상 사용이 불가하다.
•
OpenAPI spec과의 연동성 없음: API 관리의 근간을 마련하는 표준 도구는 OpenAPI이지만, Istio는 OpenAPI와의 연동성에 대한 고려가 전혀 없다(없는게 사실 당연하지만).
•
공식 문서가 제시한 해결안의 성능 이슈:
IstioClassifying Metrics Based on Request or Response 는 attributegen 이란 plugin을 통해 API 단위의 Istio metric을 얻는 방법을 논하지만, 서두에서 논했듯 성능 문제로 인해 사실 상 운영 환경에서 사용이 불가능하다.
무엇보다 중요한건, Istio Ingress Gateway는 API Gateway로서의 근원적 feature는 죄다 포함하고 있어 여기에 응용 관점의 부가 도구만 추가하면 API Gateway로서 운용도 충분히 가능하고, 이게 가능하다면 아키텍처 관점에서 최선일 듯 한데, 결정적으로 빠진 퍼즐 하나가 있다면 API 단위 관찰성이란 점이다. 즉, openapi-endpoint-filter 는 Istio Ingress Gatetway를 API Gateway로 사용할 ‘징검다리’를 제공한다.
상기 이슈 해결에 대한 그 간의 요구
사실 Istio metric을 사용하면 이러한 API 단위 관찰성에 대한 필요는 자연스럽게 떠올려지기 마련인데 그간 뚜렷한 해결안이 없던 것이 이해가 안될 지경이다. 죄다 상용 API Gateway 사용으로 해결본건지… 아래는 이 요구의 목록인데 5년 넘게 반복된 요구로 보인다.
•
•
openapi-endpoint-filter 예제
아래는 README의 내용 중 일부로, openapi-endpoint-filter 사용 시 구체적으로 어떤 결과를 나타내는지를 나타내는 예제이다.
Header injection
openapi-endpoint-filter 설정 후 request traffic 발생 시 API가 식별된 request header와 Istio metric label을 보여준다.
# openapi-endpoint-filter 설정: WasPlugin Config (일부)
pluginConfig:
services:
- name: userservice
servers:
- url: <https://api.example.com/v1>
paths:
/users/{id}: {}
# Istio로의 request 예
:method: GET
:authority: api.example.com
:path: /v1/users/42
# openapi-enpdoint-filter 연산 결과: request에 하기 header 추가
x-api-endpoint: GET /users/{id}
x-path-template: /users/{id}
x-service-name: userservice
# openapi-enpdoint-filter 연산 결과: Istio metric에 추가된 서비스, API 식별 labels
istio_requests_total{
request_endpoint="GET /users/{id}",
request_path_template="/users/{id}",
request_service="userservice",
request_method="GET", # Istio Telemetry API가 생성
request_host="api.example.com" # Istio Telemetry API가 생성
}
YAML
복사
Server variables
OpenAPI spec의 servers , variable 을 인식하여 host를 API 식별 key로 사용한 모습을 보여준다.
# openapi-endpoint-filter 설정: WasPlugin Config (일부)
pluginConfig:
services:
- name: userservice
servers:
- url: https://{env}.example.com/v1
variables:
env:
default: api
enum: [api, staging]
paths:
/users/{id}: {}
# Istio로의 request 예(동일 endpoint를 호출하지만 host가 다름)
:method: GET
:authority: api.example.com
:path: /v1/users/42
:method: GET
:authority: staging.example.com
:path: /v1/users/42
# openapi-enpdoint-filter 연산 결과: request에 하기 header 추가
x-api-endpoint: GET /users/{id}
x-path-template: /users/{id}
x-service-name: userservice
# openapi-enpdoint-filter 연산 결과: Istio metric에 추가된 서비스, API 식별 labels
istio_requests_total{
request_endpoint="GET /users/{id}",
request_path_template="/users/{id}",
request_service="userservice",
request_method="GET", # Istio Telemetry API가 생성
request_host="<api.example.com | staging.example.com>" # Istio Telemetry API가 생성
}
YAML
복사
그림 백업



