Ssoon

[4주차] 관찰 가능성(서비스 동작 이해) : Istio의 표준 메트릭 사용자 지정 본문

Istio Hands-on Study [1기]

[4주차] 관찰 가능성(서비스 동작 이해) : Istio의 표준 메트릭 사용자 지정

구구달스 2025. 4. 22. 10:09

📊 Istio의 표준 메트릭 커스터마이징하기

Istio는 서비스 간 통신을 모니터링하기 위해 기본적으로 제공되는 표준 메트릭을 통해 강력한 observability를 지원합니다. 


📋 Istio 표준 메트릭 이해하기

  • Istio는 서비스 간 통신에서 발생하는 다양한 메트릭을 자동으로 수집합니다. 대표적인 표준 메트릭은 다음과 같습니다:
Metric Name Type  Description
istio_requests_total Counter 각 요청마다 증가하는 카운터
istio_request_duration_milliseconds Distribution 요청 처리 시간의 분포
istio_request_bytes Distribution 요청 본문 크기의 분포
istio_response_bytes Distribution 응답 본문 크기의 분포
istio_request_messages_total (gRPC) Counter 클라이언트에서 받은 메시지 수를 나타내는 카운터 (gRPC)
istio_response_messages_total (gRPC) Counter 서버에서 보낸 메시지 수를 나타내는 카운터 (gRPC)
  • 예를 들어, istio_requests_total은 서비스로 들어오거나 나가는 요청 수를 카운트하는 counter 메트릭입니다.
  • Istio는 Envoy proxy의 플러그인을 활용해 메트릭을 생성, 표시, 커스터마이징합니다.
  • 이를 이해하려면 메트릭의 세 가지 핵심 개념을 알아야 합니다: Metric, Dimension, Attribute.

Istio의 표준 메트릭은 서비스 통신을 모니터링하기 위한 기본 도구입니다.


🔍 메트릭, Dimension, Attribute란?

  • Istio 메트릭을 커스터마이징하기 위해 다음 세 가지 개념을 이해하는 것이 중요합니다.

1️⃣ Metric

  • Metric서비스 간 통신에서 발생하는 telemetry 데이터를 수집하는 단위입니다. 메트릭에는 세 가지 유형이 있습니다:
    • Counter: 증가만 하는 값(예: istio_requests_total은 요청 수를 카운트).
    • Gauge: 변동하는 값(예: 현재 활성 연결 수).
    • Histogram/Distribution: 데이터 분포를 기록(예: 요청 소요 시간).
  • 예를 들어, istio_requests_total은 서비스로 들어오는(inbound) 또는 나가는(outbound) 요청 수를 기록합니다. 서비스가 양방향 요청을 처리하면 두 개의 별도 메트릭 항목이 생성됩니다.

2️⃣ Dimension

  • Dimension은 메트릭을 세분화하는 속성입니다. 예를 들어, istio_requests_total 메트릭은 다음과 같은 dimension을 가질 수 있습니다:
    • response_code: HTTP 응답 코드(예: 200, 500).
    • reporter: 메트릭을 보고하는 주체(예: destination, source).
    • destination_service: 요청 대상 서비스(예: webapp.istioinaction.svc.cluster.local).
    • connection_security_policy: 보안 정책(예: mutual_tls).
  • Dimension이 다르면 동일한 메트릭이라도 별도의 항목으로 표시됩니다. 아래는 istio_requests_total 메트릭의 예입니다: response_code가 다르므로 두 개의 별도 메트릭 항목이 생성됩니다.
istio_requests_total{
  response_code="200",
  reporter="destination",
  source_workload="istio-ingressgateway",
  destination_workload="webapp",
  request_protocol="http",
  connection_security_policy="mutual_tls"
}

istio_requests_total{
  response_code="500",
  reporter="destination",
  source_workload="istio-ingressgateway",
  destination_workload="webapp",
  request_protocol="http",
  connection_security_policy="mutual_tls"
}

3️⃣ Attribute

  • Attribute는 Envoy proxy가 런타임에 생성하는 데이터로, dimension의 값을 채우는 데 사용됩니다.
    Envoy는 다양한 attribute를 기본 제공하며, Istio는 추가적인 attribute를 제공합니다.
Attribute Description
request.path URL의 경로(path) 부분
request.url_path 쿼리 문자열을 제외한 URL의 경로(path) 부분
request.host URL의 호스트(host) 부분
request.scheme URL의 스킴(scheme) 부분 (예: "http")
request.method 요청 메서드 (예: "GET")
request.headers 소문자로 변환된 이름을 키로 하는 모든 요청 헤더
request.referer Referer 요청 헤더
request.useragent User-Agent 요청 헤더
request.time 첫 번째 바이트가 수신된 시간
request.id x-request-id 헤더 값에 해당하는 요청 ID
request.protocol 요청 프로토콜
  • Envoy의 기본 attribute 외에도 Istio의 peer-metadata filter를 통해 추가 attribute를 사용할 수 있습니다. 예를 들어:
    • upstream_peer.cluster_id: 업스트림 서비스의 클러스터 ID.
    • downstream_peer.istio_version: 다운스트림 Istio proxy의 버전.
Attribute  Description
name Pod의 이름
namespace Pod가 실행 중인 네임스페이스
labels 워크로드 라벨
owner 워크로드 소유자
workload_name 워크로드 이름
platform_metadata 접두사가 붙은 키를 가진 플랫폼 메타데이터
istio_version 프록시의 버전 식별자
mesh_id 메시의 고유 식별자
cluster_id 해당 워크로드가 속한 클러스터의 식별자
app_containers 애플리케이션 컨테이너의 짧은 이름 목록

.

  • Attribute는 upstream_peer 또는 downstream_peer 접두사를 사용해 참조합니다.
    예를 들어, 호출자의 Istio 버전을 참조하려면 downstream_peer.istio_version을 사용합니다.

Metric은 데이터를 수집하고, dimension은 데이터를 분류하며, attribute는 dimension의 값을 제공합니다.


🛠️ 메트릭 커스터마이징하기

  • Istio에서는 attribute를 활용해 메트릭의 dimension을 커스터마이징할 수 있습니다.
    예를 들어, istio_requests_total 메트릭에 새로운 dimension을 추가하거나 기존 dimension의 값을 변경할 수 있습니다.
  • 커스터마이징은 Envoy proxy의 설정을 수정하거나 Istio의 Telemetry API를 사용해 수행합니다. 구체적인 방법은 다음과 같습니다:
    • 속성 선택: 사용할 attribute(예: downstream_peer.istio_version)를 결정합니다.
    • Dimension 정의: 메트릭에 추가할 dimension을 설정합니다.
    • 설정 적용: Istio의 Telemetry 리소스나 Envoy 필터 설정을 업데이트합니다.
  • 이 과정은 Istio의 설정 파일이나 Kubernetes 리소스를 통해 구성됩니다. 

Attribute를 사용해 메트릭의 dimension을 커스터마이징하면 더 세밀한 모니터링이 가능합니다.


📌 핵심 요약

  • 표준 메트릭: istio_requests_total 같은 메트릭은 서비스 통신의 기본 telemetry를 제공합니다.
  • Metric, Dimension, Attribute:
    • Metric: Counter, Gauge, Histogram 등으로 데이터를 수집.
    • Dimension: 메트릭을 세분화하는 속성(예: response_code, destination_service).
    • Attribute: Envoy와 Istio가 제공하는 런타임 데이터로 dimension 값을 채움.
  • Attribute 종류: Envoy의 기본 attribute와 Istio의 peer-metadata filter를 통해 제공되는 attribute를 사용.
  • 커스터마이징: Attribute를 활용해 메트릭의 dimension을 사용자 정의하여 원하는 데이터를 수집.
  • 다음 단계: 설정 파일을 수정해 실제로 메트릭을 커스터마이징합니다.

📊 기존 Istio 메트릭 설정하기

Istio의 메트릭은 기본적으로 Envoy proxy의 stats 플러그인을 통해 구성되며, 이를 커스터마이징하여 원하는 데이터를 수집할 수 있습니다.


🔍 Istio의 기본 메트릭 설정 확인

  • Istio를 설치하면 기본적으로 EnvoyFilter 리소스를 통해 메트릭 관련 설정이 적용됩니다.
    이 설정은 Envoy proxy의 stats 플러그인을 사용해 메트릭을 생성합니다.
    설치된 EnvoyFilter를 확인하려면 다음 명령어를 실행하세요:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get envoyfilter -n istio-system
NAME                    AGE
stats-filter-1.13       3h4m
stats-filter-1.14       3h4m
stats-filter-1.15       3h4m
stats-filter-1.16       3h4m
stats-filter-1.17       3h4m
tcp-stats-filter-1.13   3h4m
tcp-stats-filter-1.14   3h4m
tcp-stats-filter-1.15   3h4m
tcp-stats-filter-1.16   3h4m
tcp-stats-filter-1.17   3h4m

 

  • stats-filter-1.13을 살펴보면 아래와 같은 설정을 확인할 수 있습니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get envoyfilter stats-filter-1.13 -n istio-system -o yaml
...
spec:
  configPatches:
  - applyTo: HTTP_FILTER #HTTP 필터 레벨에서 수정
    match:
      context: SIDECAR_OUTBOUND #사이드카 프록시가 바깥쪽으로 요청을 보낼 때 적용
      listener:
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
            #HTTP 요청을 관리하는 기본 핸들러인 http_connection_manager 필터를 찾아서 수정
            subFilter:
              name: envoy.filters.http.router
            #router 필터 앞에 끼워 넣습니다.
      proxy:
        proxyVersion: ^1\.13.* #proxyVersion이 1.13대 버전인 프록시(Envoy)만 대상
    patch:
      operation: INSERT_BEFORE #router 필터 바로 전에 새 필터를 삽입(INSERT_BEFORE) 
      value:
        name: istio.stats #삽입할 필터 이름은 istio.stats
        typed_config:
          '@type': type.googleapis.com/udpa.type.v1.TypedStruct
          type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
          #Envoy에 Wasm으로 작성된 프로그램을 집어넣는 방식
          value:
            config:
              configuration:
                '@type': type.googleapis.com/google.protobuf.StringValue
                # Wasm 프로그램의 설정(configuration)
                value: |
                  {
                    "debug": "false", #디버그 모드를 끄고
                    "stat_prefix": "istio" #모든 수집한 메트릭 이름 앞에 istio_ 를 붙입니다.
                  }
              root_id: stats_outbound #Wasm 필터를 식별하는 고유 ID
              vm_config:
                code:
                  local:
                    inline_string: envoy.wasm.stats
                    #사용하려는 Wasm 코드가 envoy.wasm.stats 라는 이름으로 Envoy 안에 내장
                runtime: envoy.wasm.runtime.null #null runtime을 사용
                vm_id: stats_outbound
                #실제 Wasm을 실행하는 건 아니고, Envoy에 이미 C++로 포팅된 버전을 "Wasm처럼" 실행
...
  • 이 설정은 istio.stats라는 WebAssembly(Wasm) 플러그인을 정의합니다.
  • 이 플러그인은 Envoy 코드베이스에 직접 컴파일되어 별도의 Wasm VM 없이 실행됩니다.
  • Wasm VM에서 실행하려면 설치 시 --set values.telemetry.v2.prometheus.wasmEnabled=true 플래그를 추가해야 합니다.

Istio의 기본 메트릭은 EnvoyFilter를 통해 stats 플러그인으로 설정됩니다.


🛠️ 기존 메트릭에 새로운 Dimension 추가

istio_requests_total 메트릭에 새로운 dimension을 추가하여 더 세밀한 모니터링을 구현해보겠습니다. 예를 들어, 업그레이드 추적을 위해 업스트림 프록시의 버전(upstream_proxy_version)과 소스 메쉬 ID(source_mesh_id)를 추가하고, 불필요한 request_protocol dimension을 제거하겠습니다.

📝 IstioOperator로 Dimension 설정

  • 아래는 새로운 dimension을 추가하는 IstioOperator 설정입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/istio-operator-new-dimensions.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo #demo 프로파일을 기반으로 설치
  values:
    telemetry:
      v2: #telemetry v2 을 설정
        prometheus:
          configOverride: #기본 Prometheus 메트릭 수집 방식을 오버라이드(수정) 
            inboundSidecar: #파드(사이드카)로 들어오는 트래픽에 대해 설정.
              metrics:
              - name: requests_total #기본 requests_total 메트릭을 수정.
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version #요청을 보낸 쪽(upstream)의 Istio 버전을 메트릭 라벨로 추가
                  source_mesh_id: node.metadata['MESH_ID'] #요청을 보낸 쪽 사이드카의 MESH_ID 메타데이터를 메트릭 라벨로 추가
                tags_to_remove:
                - request_protocol #request_protocol 라벨은 메트릭에서 제거
            outboundSidecar: #파드에서 바깥쪽으로 나가는 트래픽에 대해 같은 설정 적용
              metrics:
              - name: requests_total
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version
                  source_mesh_id: node.metadata['MESH_ID']
                tags_to_remove:
                - request_protocol
            gateway: #Istio Gateway 에서 처리하는 트래픽에 대해 같은 설정 적용.
              metrics:
              - name: requests_total
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version
                  source_mesh_id: node.metadata['MESH_ID']
                tags_to_remove:
                - request_protocol
  • 이 설정은 다음과 같은 작업을 수행합니다:
    • requests_total 메트릭에 upstream_proxy_version과 source_mesh_id dimension을 추가.
    • request_protocol dimension을 제거.
    • inboundSidecar, outboundSidecar, gateway에 동일한 설정을 적용.

🚀 설정 적용

  • 다음 명령어로 IstioOperator 설정을 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/#

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/#
root@myk8s-control-plane:/# cat << EOF > istio-operator-new-dimensions.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  values:
    telemetry:
      v2:
        prometheus:
          configOverride:
            inboundSidecar:
              metrics:
              - name: requests_total
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version
                  source_mesh_id: node.metadata['MESH_ID']
                tags_to_remove:
                - request_protocol
            outboundSidecar:
              metrics:
              - name: requests_total
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version
                  source_mesh_id: node.metadata['MESH_ID']
                tags_to_remove:
                - request_protocol
            gateway:
              metrics:
              - name: requests_total
                dimensions:
                  upstream_proxy_version: upstream_peer.istio_version
                  source_mesh_id: node.metadata['MESH_ID']
                tags_to_remove:
                - request_protocol
EOF

root@myk8s-control-plane:/# istioctl install -f istio-operator-new-dimensions.yaml -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
- Pruning removed resources                                                                                       Removed HorizontalPodAutoscaler:istio-system:istiod.
  Removed HorizontalPodAutoscaler:istio-system:istio-ingressgateway.
✔ Installation complete                                                                                         Making this installation the default for injection and validation.

Thank you for installing Istio 1.17.  Please take a few minutes to tell us about your install/upgrade experience!  https://forms.gle/hMHGiwZHPU7UQRWe9
  • 적용 후, istioctl은 내부적으로 stats-filter-1.13 EnvoyFilter를 업데이트합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get envoyfilter stats-filter-1.13 -n istio-system -o yaml
...
    patch:
      operation: INSERT_BEFORE
...
                value: |
                  {"metrics":[{"dimensions":{"source_mesh_id":"node.metadata['MESH_ID']","upstream_proxy_version":"upstream_peer.istio_version"},"name":"requests_total","tags_to_remove":["request_protocol"]}]}
              root_id: stats_outbound
              vm_config:
                code:
                  local:
                    inline_string: envoy.wasm.stats
                runtime: envoy.wasm.runtime.null
                vm_id: stats_outbound
  - applyTo: HTTP_FILTER
...
                value: |
                  {"metrics":[{"dimensions":{"source_mesh_id":"node.metadata['MESH_ID']","upstream_proxy_version":"upstream_peer.istio_version"},"name":"requests_total","tags_to_remove":["request_protocol"]}]}
              root_id: stats_inbound
              vm_config:
                code:
                  local:
                    inline_string: envoy.wasm.stats
                runtime: envoy.wasm.runtime.null
                vm_id: stats_inbound
  - applyTo: HTTP_FILTER
...
                value: |
                  {"metrics":[{"dimensions":{"source_mesh_id":"node.metadata['MESH_ID']","upstream_proxy_version":"upstream_peer.istio_version"},"name":"requests_total","tags_to_remove":["request_protocol"]}]}
...

Figure: Behind the Scenes
IstioOperator를 통해 새로운 dimension을 추가하면 stats-filter-1.13 EnvoyFilter가 자동으로 업데이트됩니다.

IstioOperator를 사용해 새로운 dimension을 추가하고 불필요한 dimension을 제거합니다.


🔧 Pod에 Annotation 추가

  • 새로운 dimension이 메트릭에 반영되려면 Istio proxy가 이를 인식하도록 Pod에 annotation을 추가해야 합니다. 이 annotation은 deployment의 spec.template.metadata에 추가됩니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/webapp-deployment-extrastats.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: webapp
  name: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |- 
        #사이드카 proxy의 설정을 커스터마이즈 하겠다; EnvoyFilter나 텔레메트리 설정을 별도로 건드리지 않고 Pod별로 적용
          extraStatTags: #Envoy가 수집하는 메트릭(stat) 에 추가 태그(dimension) 를 붙이라는 의미
          - "upstream_proxy_version" #upstream_proxy_versio 라는 라벨을 추가
          - "source_mesh_id" #source_mesh_id 라는 라벨을 추가
      labels:
        app: webapp
    spec:
      containers:
      - env:
        - name: KUBERNETES_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: istioinaction/webapp:latest
        imagePullPolicy: IfNotPresent
        name: webapp
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        securityContext:
          privileged: false
  • 이 설정을 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f ch7/metrics/webapp-deployment-extrastats.yaml
deployment.apps/webapp configured

Pod annotation을 추가해 새로운 dimension을 Istio proxy에 반영합니다.


🌊 메트릭 생성 및 확인

  • 설정을 적용한 후, 서비스에 요청을 보내 메트릭을 생성합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
  • webapp 서비스의 Istio proxy에서 메트릭을 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy \
-- curl localhost:15000/stats/prometheus | grep istio_requests_total
# TYPE istio_requests_total counter
istio_requests_total{reporter="destination",source_workload="istio-ingressgateway",source_canonical_service="istio-ingressgateway",source_canonical_revision="latest",source_workload_namespace="istio-system",source_principal="spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account",source_app="istio-ingressgateway",source_version="unknown",source_cluster="Kubernetes",destination_workload="webapp",destination_workload_namespace="istioinaction",destination_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp",destination_app="webapp",destination_version="",destination_service="webapp.istioinaction.svc.cluster.local",destination_canonical_service="webapp",destination_canonical_revision="latest",destination_service_name="webapp",destination_service_namespace="istioinaction",destination_cluster="Kubernetes",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="mutual_tls",source_mesh_id="cluster.local",upstream_proxy_version="unknown"} 83
istio_requests_total{reporter="source",source_workload="webapp",source_canonical_service="webapp",source_canonical_revision="latest",source_workload_namespace="istioinaction",source_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp",source_app="webapp",source_version="",source_cluster="Kubernetes",destination_workload="catalog",destination_workload_namespace="istioinaction",destination_principal="spiffe://cluster.local/ns/istioinaction/sa/catalog",destination_app="catalog",destination_version="v1",destination_service="catalog.istioinaction.svc.cluster.local",destination_canonical_service="catalog",destination_canonical_revision="v1",destination_service_name="catalog",destination_service_namespace="istioinaction",destination_cluster="Kubernetes",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="unknown",source_mesh_id="cluster.local",upstream_proxy_version="1.17.8"} 83

 

  • 출력에서 upstream_proxy_version과 source_mesh_id가 추가되고, request_protocol이 제거된 것을 확인할 수 있습니다.

새로운 dimension이 포함된 메트릭을 생성하고 확인합니다.


🆕 새로운 Telemetry API 사용

  • Istio 1.12부터 도입된 Telemetry API를 사용하면 메트릭 설정을 더 유연하게 제어할 수 있습니다. IstioOperator는 글로벌 설정을 변경하지만, Telemetry API는 특정 namespace 또는 workload에만 적용할 수 있습니다.

Figure: Telemetry API
Telemetry API는 Istio 1.13 기준 alpha 단계로, 변경될 수 있습니다. 자세한 내용은 Istio 문서를 참조하세요.

  • Telemetry API를 사용한 설정 예시는 다음과 같습니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/v2/add-dimensions-telemetry.yaml
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: add-dimension-tags
  namespace: istioinaction
spec:
  metrics:
  - providers:
      - name: prometheus
    overrides:
      - match:
          metric: REQUEST_COUNT
          mode: CLIENT_AND_SERVER
        disabled: false
        tagOverrides:
          upstream_proxy_version:
            operation: UPSERT
            value: upstream_peer.istio_version
          source_mesh_id:
            operation: UPSERT
            value: node.metadata['MESH_ID']
          request_protocol:
            operation: REMOVE

 

Telemetry API를 사용하면 특정 namespace나 workload에 메트릭 설정을 세밀하게 적용할 수 있습니다.

 


📌 핵심 요약

  • 기본 설정: Istio는 EnvoyFilter(stats-filter-1.13)를 통해 메트릭을 stats 플러그인으로 구성.
  • Dimension 추가: IstioOperator를 사용해 upstream_proxy_version, source_mesh_id 같은 새로운 dimension을 추가하고 request_protocol을 제거.
  • Pod Annotation: extraStatTags annotation을 Pod에 추가해 새로운 dimension을 반영.
  • 메트릭 확인: 서비스 요청 후 proxy에서 메트릭을 확인해 새로운 dimension이 적용되었는지 검증.
  • Telemetry API: 특정 namespace나 workload에 메트릭 설정을 적용하는 유연한 방법 제공.

📈 새로운 Istio 메트릭 생성하기

Istio에서는 기존 메트릭의 dimension을 커스터마이징하는 것뿐만 아니라, 새로운 메트릭을 직접 정의할 수도 있습니다. 예를 들어, HTTP GET 요청 수를 카운트하는 istio_get_calls 메트릭을 생성하는 과정을 단계별로 다룹니다.


🛠️ 새로운 메트릭 정의하기

  • Istio의 stats 플러그인을 활용하면 새로운 메트릭을 정의할 수 있습니다.
    여기서는 HTTP GET 요청 수를 카운트하는 istio_get_calls 메트릭을 생성합니다.
    이 메트릭은 IstioOperator 설정을 통해 구성됩니다.

📝 IstioOperator로 메트릭 정의

  • 아래는 새로운 메트릭을 정의하는 IstioOperator 설정입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$  cat ch7/metrics/istio-operator-new-metric.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  values:
    telemetry:
      v2:
        prometheus:
          configOverride:
            inboundSidecar: #들어오는 요청(받는 쪽)
              definitions:
              - name: get_calls
                type: COUNTER #숫자를 하나씩 증가시키는 타입
                value: "(request.method.startsWith('GET') ? 1 : 0)"
                #request.method가 GET으로 시작하면 1, 아니면 0으로 기록; GET 요청만 세겠다
            outboundSidecar: #나가는 요청(보내는 쪽)
              definitions:
              - name: get_calls
                type: COUNTER
                value: "(request.method.startsWith('GET') ? 1 : 0)"
            gateway: #Istio Ingress/Egress Gateway 트래픽
              definitions:
              - name: get_calls
                type: COUNTER
                value: "(request.method.startsWith('GET') ? 1 : 0)"
  • 이 설정의 주요 내용을 살펴보면:
    • name: 메트릭 이름은 get_calls로 정의하며, Istio가 자동으로 istio_ 접두사를 추가해 istio_get_calls로 생성됩니다.
    • type: 메트릭 유형은 COUNTER로 설정하며, GAUGE와 HISTOGRAM도 가능합니다.
    • value: Common Expression Language(CEL, 공식 문서)를 사용해 메트릭 값을 정의합니다. 여기서는 request.method가 'GET'으로 시작하면 1을, 아니면 0을 반환합니다.

🚀 설정 적용

  • 다음 명령어로 IstioOperator 설정을 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# cat << EOF > istio-operator-new-metric.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  values:
    telemetry:
      v2:
        prometheus:
          configOverride:
            inboundSidecar:
              definitions:
              - name: get_calls
                type: COUNTER
                value: "(request.method.startsWith('GET') ? 1 : 0)"
            outboundSidecar:
              definitions:
              - name: get_calls
                type: COUNTER
                value: "(request.method.startsWith('GET') ? 1 : 0)"
            gateway:
              definitions:
              - name: get_calls
                type: COUNTER
                value: "(request.method.startsWith('GET') ? 1 : 0)"
EOF
root@myk8s-control-plane:/# istioctl install -f istio-operator-new-metric.yaml -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete                                                                                         Making this installation the default for injection and validation.

Thank you for installing Istio 1.17.  Please take a few minutes to tell us about your install/upgrade experience!  https://forms.gle/hMHGiwZHPU7UQRWe9

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get istiooperator -n istio-system installed-state -o yaml  | grep -A2 get_calls$
              - name: get_calls
                type: COUNTER
                value: '(request.method.startsWith(''GET'') ? 1 : 0)'
--
              - name: get_calls
                type: COUNTER
                value: '(request.method.startsWith(''GET'') ? 1 : 0)'
--
              - name: get_calls
                type: COUNTER
                value: '(request.method.startsWith(''GET'') ? 1 : 0)'
  • 이 명령은 inboundSidecar, outboundSidecar, gateway에 새로운 istio_get_calls 메트릭을 추가합니다.

IstioOperator를 사용해 새로운 메트릭 istio_get_calls를 정의하고 적용합니다.


🔧 Pod에 Annotation 추가

  • 새로운 메트릭이 Istio proxy에서 노출되려면 Pod에 sidecar.istio.io/statsInclusionPrefixes annotation을 추가해야 합니다. 이 annotation은 deployment의 spec.template.metadata에 설정됩니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/webapp-deployment-new-metric.yaml
...
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |-
          proxyStatsMatcher:
            inclusionPrefixes:
            - "istio_get_calls"
      labels:
        app: webapp
...
  • 이 설정을 적용합니다:
    • 이 annotation은 Istio proxy가 istio_get_calls 메트릭을 Prometheus로 노출하도록 지시합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl -n istioinaction apply -f ch7/metrics/webapp-deployment-new-metric.yaml
deployment.apps/webapp configured

Pod annotation을 추가해 새로운 메트릭을 Istio proxy에 노출합니다.


🌊 메트릭 생성 및 확인

  • 설정을 적용한 후, 서비스에 HTTP GET 요청을 보내 메트릭을 생성합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
  • webapp 서비스의 Istio proxy에서 메트릭을 확인합니다.
  • istio_get_calls 메트릭이 생성되었으며, 현재까지 GET 메서드 요청이 160번 있었다는 의미입니다.
    현재는 dimension이 설정되지 않았으므로 메트릭만 표시됩니다. 
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy -- curl localhost:15000/stats/prometheus | grep istio_get_calls
# TYPE istio_get_calls counter
istio_get_calls{} 160

 

서비스 요청을 보내 새로운 메트릭을 생성하고 proxy에서 확인합니다.


🔍 더 세밀한 메트릭 생성 가능성

  • 시스템 내 모든 GET 요청 수를 카운트하는 간단한 메트릭을 생성했습니다.
    하지만 Istio의 stats 플러그인은 더 세밀한 메트릭을 생성할 수 있는 강력한 기능을 제공합니다.
    예를 들어, catalog 서비스의 /items 엔드포인트로 들어오는 GET 요청만 카운트하려면 다음과 같이 CEL 표현식을 수정할 수 있습니다:
value: "(request.method.startsWith('GET') && request.path.startsWith('/items') ? 1 : 0)"
  • 이처럼 새로운 dimension과 attribute를 추가해 원하는 조건에 맞는 메트릭을 정의할 수 있습니다. 

Istio stats 플러그인은 CEL을 사용해 세밀한 메트릭을 생성할 수 있습니다.


📌 핵심 요약

  • 새로운 메트릭 정의: IstioOperator를 사용해 istio_get_calls 메트릭을 정의하며, CEL로 GET 요청 수를 카운트.
  • Pod Annotation: statsInclusionPrefixes annotation을 추가해 새로운 메트릭을 proxy에 노출.
  • 메트릭 확인: 서비스 요청 후 proxy에서 istio_get_calls 메트릭을 확인.
  • 확장 가능성: CEL과 attribute를 활용해 특정 엔드포인트나 조건에 맞는 세밀한 메트릭 생성 가능.
  • 다음 단계: dimension과 attribute를 추가해 메트릭을 더 커스터마이징.

📊 새로운 Attribute로 Istio 호출 그룹화하기

Istio에서는 기존 attribute를 조합해 새로운 attribute를 만들어 메트릭을 더 세밀하게 관리할 수 있습니다. 


🛠️ 새로운 Attribute 생성하기

  • Istio의 attribute-gen 플러그인을 사용하면 기존 attribute를 조합해 새로운 attribute를 생성할 수 있습니다.
  • request.url_path와 request.method를 조합 /items 엔드포인트에 대한 GET, POST, DELETE 요청을 구분하는 istio_operationId attribute를 만듭니다.

📝 Attribute-gen 플러그인 설정

  • 아래는 attribute-gen 플러그인을 설정하는 EnvoyFilter의 주요 부분입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/attribute-gen.yaml
...
    patch:
      operation: INSERT_BEFORE
      value:
        name: istio.attributegen
        #필터 이름은 istio.attributegen
        typed_config:
          '@type': type.googleapis.com/udpa.type.v1.TypedStruct
          type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
          #Envoy의 Wasm 플러그인을 이용해서 동작
          value:
            config:
              configuration:
                '@type': type.googleapis.com/google.protobuf.StringValue
                value: |
                  {
                    "attributes": [
                      {
                        "output_attribute": "istio_operationId", #생성할 Attribute 이름은 istio_operationId
                        "match": [ #요청 URL과 메서드에 따라 istio_operationId 값을 다르게 설정
                         {
                           "value": "getitems", #생성되는 Attribute 값
                           "condition": "request.url_path == '/items' && request.method == 'GET'"
                         },
                         {
                           "value": "createitem", #생성되는 Attribute 값
                           "condition": "request.url_path == '/items' && request.method == 'POST'"
                         },
                         {
                           "value": "deleteitem", #생성되는 Attribute 값
                           "condition": "request.url_path == '/items' && request.method == 'DELETE'"
                         }
                       ]
                      }
                    ]
                  }
...

 

  • output_attribute: 새로운 attribute 이름(istio_operationId)을 정의.
  • match: 조건에 따라 istio_operationId의 값을 설정.
    • /items에 대한 GET 요청은 getitems.
    • /items에 대한 POST 요청은 createitem.
    • /items에 대한 DELETE 요청은 deleteitem.

🚀 EnvoyFilter 적용

  • attribute-gen.yaml 을 적용하기 전에 proxyVersion: ^1\.16.* 을 설치된 istio 버전에 맞게 1.16 혹은 1.17 로 수정.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane istioctl version
client version: 1.17.8
control plane version: 1.17.8
data plane version: 1.17.8 (4 proxies)
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ vi ch7/metrics/attribute-gen.yaml
...
      proxy:
        proxyVersion: ^1\.17.*
  • 다음 명령어로 EnvoyFilter를 적용해 webapp 서비스의 outbound 호출에 attribute-gen 플러그인을 추가합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch7/metrics/attribute-gen.yaml -n istioinaction
envoyfilter.networking.istio.io/attribute-gen-example created

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get envoyfilter -n istioinaction
NAME                    AGE
attribute-gen-example   19s

attribute-gen 플러그인을 사용해 새로운 istio_operationId attribute를 생성합니다.


📈 새로운 Dimension으로 메트릭 확장

  • 새로운 istio_operationId attribute를 활용해 istio_requests_total 메트릭에 upstream_operation dimension을 추가합니다. 이를 통해 /items API 호출을 더 세밀하게 추적할 수 있습니다.

📝 Stats 플러그인 설정

  • 아래는 upstream_operation dimension을 추가하는 IstioOperator 설정입니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/istio-operator-new-attribute.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  values:
    telemetry:
      v2:
        prometheus:
          configOverride:
            outboundSidecar:
              metrics:
              - name: requests_total #기본 제공 메트릭인 requests_total 을 수정
                dimensions:
                  upstream_operation: istio_operationId
                  #requests_total 메트릭에 새로운 Dimension (라벨) upstream_operation을 추가
                  #이 upstream_operation 값은 요청에 붙은 istio_operationId Attribute 값을 사용

🚀 설정 적용

  • 다음 명령어로 새로운 dimension 설정을 적용합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# cat << EOF > istio-operator-new-attribute.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  values:
    telemetry:
      v2:
        prometheus:
          configOverride:
            outboundSidecar:
              metrics:
              - name: requests_total
                dimensions:
                  upstream_operation: istio_operationId # 새 디멘션
EOF
root@myk8s-control-plane:/# istioctl install -f istio-operator-new-attribute.yaml -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete                                                                                         Making this installation the default for injection and validation.

Thank you for installing Istio 1.17.  Please take a few minutes to tell us about your install/upgrade experience!  https://forms.gle/hMHGiwZHPU7UQRWe9

새로운 upstream_operation dimension을 istio_requests_total 메트릭에 추가합니다.


🔧 Pod에 Annotation 추가

  • 새로운 dimension이 메트릭에 반영되려면 Pod에 extraStatTags annotation을 추가해야 합니다.
    이 annotation은 deployment의 spec.template.metadata에 설정됩니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch7/metrics/webapp-deployment-extrastats-new-attr.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: webapp
  name: webapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |-
          extraStatTags:
          - "upstream_operation"
      labels:
        app: webapp
    spec:
      containers:
      - env:
        - name: KUBERNETES_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image: istioinaction/webapp:latest
        imagePullPolicy: IfNotPresent
        name: webapp
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        securityContext:
          privileged: false
          
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl -n istioinaction apply -f ch7/metrics/webapp-deployment-extrastats-new-attr.yaml
deployment.apps/webapp configured
  • 이 설정은 Istio proxy가 upstream_operation dimension을 포함한 메트릭을 생성하도록 지시합니다.

Pod annotation을 추가해 새로운 dimension을 Istio proxy에 반영합니다.


🌊 메트릭 생성 및 확인

  • 설정을 적용한 후, 서비스에 요청을 보내 메트릭을 생성합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
  • webapp 서비스의 Istio proxy에서 메트릭을 확인합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy -- curl localhost:15000/stats/prometheus | grep istio_requests_total
# TYPE istio_requests_total counter
istio_requests_total{reporter="destination",source_workload="istio-ingressgateway",source_canonical_service="istio-ingressgateway",source_canonical_revision="latest",source_workload_namespace="istio-system",source_principal="spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account",source_app="istio-ingressgateway",source_version="unknown",source_cluster="Kubernetes",destination_workload="webapp",destination_workload_namespace="istioinaction",destination_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp",destination_app="webapp",destination_version="",destination_service="webapp.istioinaction.svc.cluster.local",destination_canonical_service="webapp",destination_canonical_revision="latest",destination_service_name="webapp",destination_service_namespace="istioinaction",destination_cluster="Kubernetes",request_protocol="http",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="mutual_tls"} 10
istio_requests_total{reporter="source",source_workload="webapp",source_canonical_service="webapp",source_canonical_revision="latest",source_workload_namespace="istioinaction",source_principal="spiffe://cluster.local/ns/istioinaction/sa/webapp",source_app="webapp",source_version="",source_cluster="Kubernetes",destination_workload="catalog",destination_workload_namespace="istioinaction",destination_principal="spiffe://cluster.local/ns/istioinaction/sa/catalog",destination_app="catalog",destination_version="v1",destination_service="catalog.istioinaction.svc.cluster.local",destination_canonical_service="catalog",destination_canonical_revision="v1",destination_service_name="catalog",destination_service_namespace="istioinaction",destination_cluster="Kubernetes",request_protocol="http",response_code="200",grpc_response_status="",response_flags="-",connection_security_policy="unknown",upstream_operation="getitems"} 10

 

  • 출력에서 upstream_operation="getitems"가 추가된 것을 확인할 수 있습니다. 이는 /items 엔드포인트로의 GET 요청이 추적되고 있음을 보여줍니다.

새로운 dimension이 포함된 메트릭을 생성하고 proxy에서 확인합니다.


📚 Istio 메트릭의 중요성

  • 마이크로서비스 아키텍처에서는 서비스 간 네트워크 통신이 많아질수록 문제가 발생할 가능성이 높아집니다. Istio는 개발자가 애플리케이션 코드에 별도의 로직을 추가하지 않아도 golden-signal metrics(latency, throughput, errors, saturation)를 수집할 수 있게 해줍니다. 
  • Istio는 성공률, 실패율, 재시도 횟수, 레이턴시 같은 네트워크 메트릭을 자동으로 수집하며, 애플리케이션 또는 비즈니스 레벨 메트릭과 함께 사용할 수 있습니다. 

Istio는 golden-signal metrics를 자동으로 수집해 마이크로서비스 모니터링을 간소화합니다.


📌 핵심 요약

  • 새로운 Attribute: attribute-gen 플러그인을 사용해 istio_operationId attribute를 생성해 /items API 호출을 구분.
  • 새로운 Dimension: istio_requests_total 메트릭에 upstream_operation dimension을 추가해 호출을 세밀하게 추적.
  • Pod Annotation: extraStatTags annotation을 추가해 새로운 dimension을 proxy에 반영.
  • 메트릭 확인: 서비스 요청 후 proxy에서 upstream_operation dimension이 포함된 메트릭 확인.
  • Istio의 가치: golden-signal metrics를 자동 수집해 마이크로서비스 모니터링을 간소화하며, Grafana나 Kiali로 시각화 가능.

 

Comments