이번 포스팅에서는 Istio의 Observability(관찰 가능성) 기능을 깊이 있게 살펴보자. 기존에 addon으로 간단히 구성했던 모니터링 도구들은 주로 샘플 실습용 manifest에 불과하며, 실제 운영 환경에서는 별도의 도구 설치와 세부적인 설정이 필요하다. 이번에는 Prometheus, Grafana, Jaeger, Kiali 같은 도구들을 Istio와 연동해 운영 환경에서 어떻게 Observability를 구축할 수 있는지 단계별로 알아본다.
1. Istio에서의 observability란?
Istio에서의 Observability는 마이크로서비스 환경에서 특히 강력한 역할을 한다. Istio는 각 서비스에 Envoy 프록시를 사이드카로 주입하여, 애플리케이션 코드를 수정하지 않고도 네트워크 트래픽을 가로채 메트릭, 로그, 트레이스 데이터를 자동으로 수집할 수 있다.
Envoy는 애플리케이션과 서비스 간 요청·응답의 모든 흐름을 통과하기 때문에, 요청 수, 지연 시간, 오류율 같은 상세한 애플리케이션 레벨 메트릭을 가장 이상적으로 수집할 수 있는 위치에 있다. 덕분에 개발자는 코드 수정이나 추가 작업 없이 인프라 차원에서 통계 데이터를 수집하고 서비스 상태를 정밀 분석할 수 있다.
2. Istio 메트릭 살펴보기
Istio가 기본적으로 제공하는 메트릭이 무엇인지, 알아보자.
Istio 표준 메트릭(Standard Metrics)
Istio 표준 메트릭은 각 Envoy 프록시의 관리 포트(localhost:15000/stats) 엔드포인트에서 기본적으로 노출된다. istio가 제공하는 표준 메트릭 수집을 통해, 추가적으로 메트릭 수집을 할 필요 없을 정도로 정보가 많다.
대표적인 표준 메트릭은 다음과 같다.
istio_requests_total | 총 HTTP/gRPC 요청 수 (카운터) |
istio_request_duration_milliseconds | 요청 처리 시간의 분포 (히스토그램) |
istio_tcp_sent_bytes_total | 전송한 TCP 바이트 수 (카운터) |
istio_tcp_received_bytes_total | 수신한 TCP 바이트 수 (카운터) |
초기화 및 실습환경 구성
메트릭을 수집하기 위해 실습 환경 구성한다.
# istioinaction 네임스페이스 초기화
kubectl delete -n istioinaction deploy,svc,gw,vs,dr,envoyfilter --all
# catalog 앱 기동
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
# webapp 앱 기동
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
# gateway, virtualservice 설정
kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction
# 확인
kubectl get deploy,pod,svc,ep,gw,vs -n istioinaction
# 호출테스트
curl -s http://webapp.istioinaction.io:30000
curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
curl -s http://webapp.istioinaction.io:30000/api/catalog | jq
엔보이 프록시를 통해 기본 메트릭을 확인
kubectl exec -it deploy/catalog -c istio-proxy -n istioinaction -- curl localhost:15000/stats
프록시에서 엔보이 통계를 더 많이 보고하도록 설정하기 (확장 메트릭)
Istio에서 기본 메트릭 외에 더 많은 세부 메트릭을 보고 싶다면 Envoy 프록시의 /stats 엔드포인트에 추가 메트릭을 노출하도록 설정할 수 있습니다. 다만 메시 전체의 메트릭 양이 늘어나면 Prometheus 같은 메트릭 수집 시스템에 과부하를 줄 수 있으니, 신중하게 적용해야 한다.
확장 메트릭을 적용하는 방법은 크게 세 가지가 있다.
방법 1 : IstioOperator 명세
- 첫 번째 방법은 IstioOperator 명세를 사용하는 것이다. 이 방법은 메시 전체에 적용되며, proxyStatsMatcher 설정에서 보고할 메트릭의 prefix를 지정할 수 있다.
- 예를 들어,
cluster.outbound|80||catalog.istioinaction
과 같은 prefix를 추가하면 해당 메트릭들이 기본 세트와 함께 수집된다 - 이 방식은 간단하지만, 메시 전반에 적용되므로 신중하게 고려해야 한다.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: control-plane
spec:
profile: demo
meshConfig:
defaultConfig: # Defines the default proxy configuration for all services
proxyStatsMatcher: # Customizes the reported metrics
inclusionPrefixes: # Metrics matching the prefix will be reported alongside the default ones.
- "cluster.outbound|80||catalog.istioinaction"
방법 2: 해당 워크로드 별 명세
- 두 번째는 워크로드별로 어노테이션을 설정하는 방식이다.
- Kubernetes Deployment 같은 워크로드에 proxy.istio.io/config 어노테이션을 추가해 특정 메트릭 prefix만 선택적으로 포함시킨다.
- 메시 전체가 아니라 워크로드 단위로 조절할 수 있어서 훨씬 안전하고 권장되는 방법이다.
# cat ch7/webapp-deployment-stats-inclusion.yaml
...
template:
metadata:
annotations:
proxy.istio.io/config: |-
proxyStatsMatcher:
inclusionPrefixes:
- "cluster.outbound|80||catalog.istioinaction"
labels:
app: webapp
방법 3 : Telemtery API 활용
- 세 번째는 Telemetry API를 활용하는 방식이다.
- 특정 네임스페이스에서 특정 앱의 메트릭만 Prometheus로 수집하거나 액세스 로그를 켜는 것도 이 API로 제어할 수 있다.
- Istio 1.11 이상에서는 Telemetry API로 서비스, 워크로드, 네임스페이스 단위로 메트릭, 로깅, 트레이싱 정책을 세부적으로 커스터마이징할 수 있다.
저번 포스팅에서는 엑세스 로그를 활성화했을 때, Telemetry를 사용해 보았는데, Metric 수집 및 트레이싱 정책도 설정 가능하다.
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: ratings-metrics
namespace: bookinfo
spec:
selector:
matchLabels:
app: ratings
metrics:
- providers:
- name: prometheus
# AccessLog
# accessLogging:
# - providers:
# - name: envoy
# disabled: false
...
이번 실습에서는 방법 2 (워크로드별 어노테이션 설정) 을 사용해 webapp 서비스 애플리케이션에 확장 메트릭을 적용한다.
적용 전에는 엔드포인트(proxy:15000/stats)에서 볼 수 없었던 다양한 메트릭들이 적용 후 조회 가능해진다.
예를 들어, 특정 outbound 클러스터나 요청 경로별로 세분화된 통계가 표시되며, 기본 메트릭 외에 추가로 수집된 항목들이 눈에 띈다.
이번에는 확장 메트릭 적용 후 주목할 만한 주요 메트릭들을 살펴본다.
주요 메트릭 조회 1 - cluster_name.internal.*
- Envoy는 트래픽의 출처가 내부인지 외부인지 구분한다.
- 내부는 메시 내부에서 발생한 트래픽이고, 외부는 인그레스 게이트웨이를 통해 메시로 들어온 외부 트래픽이다.
- 이 메트릭을 통해 메시 내부에서 시작해 성공적으로 처리된 요청의 개수를 확인할 수 있다. 내부 트래픽의 상태와 서비스 간 상호작용을 점검할 때 매우 유용하다.
주요 메트릭 조회 2 - cluster_name.ssl.*
- 이 메트릭은 트래픽이 TLS를 사용해 업스트림 클러스터로 전달되는지를 보여주며, cipher, curve 같은 TLS 커넥션 관련 세부 정보도 알 수 있다.
- 보안이 중요한 환경에서 SSL/TLS 관련 동작을 모니터링하고 문제를 빠르게 찾아내는 데 도움이 된다.
주요 메트릭 조회 3 - upstream.*
- upstream_cx와 upstream_rq는 네트워크 상에서 발생하는 커넥션과 요청 관련 정보를 상세히 제공한다.
- 예를 들어, 업스트림 커넥션 수, 요청 수, 실패율 같은 데이터를 통해 서비스 간 통신의 신뢰성과 성능을 더 정밀하게 분석할 수 있다.
컨트롤 플레인의 메트릭 조회(citadel, pilot, xds)
Istio의 컨트롤 플레인인 istiod는 또한 자세한 메트릭을 제공한다. 예를 들면, 데이터 플레인 프록시와 설정을 몇 번 동기화했는지, 동기화에 걸린 시간, 잘못된 설정이나 인증서 발급 및 갱신 관련 정보 등이 포함된다.
컨트롤 플레인 메트릭은 기본적으로 15014 포트에서 노출된다. 이 포트는 Istio control-plane 메트릭 전용 포트로, 프로메테우스도 해당 포트로 메트릭을 긁어간다.
control-plane 주요 메트릭 조회 1 - convergence_time
- 이 메트릭은 설정을 프록시에 밀어 넣고 동기화하는 데 걸린 시간의 분포를 보여준다.
- le 값은 ‘less than or equal to’(이하)를 의미한다. 지연이 발생할 경우 0.5초 이상의 값으로 분포가 늘어날 수 있다
control-plane 주요 메트릭 조회 2 - service
- 현재 컨트롤 플레인에 등록된 서비스 개수, 사용자가 설정한 VirtualService 리소스 개수, 연결된 프록시 개수를 나타낸다.
- 쿠버네티스 API와 통합되기 때문에, 관련 서비스나 워크로드 상태도 함께 조회할 수 있다.
control-plane 주요 메트릭 조회 3 - xds
- xDS API별 업데이트 횟수를 보여준다. xDS는 CDS, EDS, LDS/RDS, SDS 등으로 구성되며, Envoy의 설정을 동적으로 업데이트하는 데 사용된다.
- 이 메트릭을 통해 어떤 API에서 얼마나 자주 업데이트가 발생하는지 파악할 수 있다.
3. Prometheus로 Istio 메트릭 수집하기
Istio 프록시는 기본적으로 Prometheus 메트릭을 노출한다. 메트릭은 주로 두 가지 포트에서 확인할 수 있다.
- 15090 → Envoy 프록시 메트릭. xDS 상태, 커넥션 상태, HTTP 상태, outlier 상태, 헬스체크, 서킷 브레이커 상태 등.``
- 15020 → Envoy 메트릭을 집계하고 노출하며, 자체 메트릭과 애플리케이션 메트릭(설정된 경우)까지 함께 포함한다. 또한 Envoy, DNS 프록시 헬스체크, 그리고 pilot-agent 디버깅용 엔드포인트(CPU 프로파일, 메모리 정보 등)를 제공한다.
중요한 점은, Istio 프록시가 주입된 모든 애플리케이션에서 이 Prometheus 메트릭들이 자동으로 노출된다는 것이다. 이를 통해 추가 설정 없이도 Prometheus에서 메트릭을 수집할 수 있다.
Prometheus 설치
이번 실습에서는 Istio에서 제공하는 기본 addon Prometheus를 사용하지 않고, kube-prometheus-stack Helm chart Prometheus를 구축한다. kube-prometheus-stack은 prometheus-operator를 포함하고 있어 PrometheusRule CRD를 통해 선언적으로 Istio 관련 메트릭 수집을 설정할 수 있다. Grafana도 함께 구성해 시각화까지 가능하다.
kube-prometheus-stack 설치
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
#
cat ch7/prom-values.yaml
open ch7/prom-values.yaml
cat << EOF > prom-values-2.yaml
prometheusOperator:
tls:
enabled: false
admissionWebhooks:
patch:
enabled: false
prometheus:
service:
type: NodePort
nodePort: 30001
grafana:
service:
type: NodePort
nodePort: 30002
EOF
# helm 설치
kubectl create ns prometheus
helm install prom prometheus-community/kube-prometheus-stack --version 13.13.1 \
-n prometheus -f ch7/prom-values.yaml -f prom-values-2.yaml
설치 후, PrometheusRule CRD 및 ServiceMonitor 리소스 확인
Prometheus가 Istio 워크로드 메트릭을 수집하도록 설정
기본 배포된 Prometheus에서는 Istio 관련 메트릭이 자동으로 수집되지 않는다.
따라서, 새로 배포한 Prometheus는 Istio의 데이터 플레인과 컨트롤 플레인 메트릭을 긁어올 방법을 따로 설정해줘야 한다.
이를 위해 Prometheus Operator의 ServiceMonitor와 PodMonitor 커스텀 리소스를 사용한다.
ServiceMonitor로 Istio 컨트롤 플레인 수집 설정
- Istio 컨트롤 플레인 구성 요소(Pilot 등)에서 메트릭을 수집하려면 아래와 같이 ServiceMonitor 리소스를 적용한다.
- 이 설정은 Istio의 pilot 서비스에서 15014 포트로 메트릭을 긁어오고, Prometheus에 등록된 잡(job) 이름은 istio로 표시된다
# cat ch7/service-monitor-cp.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istio-component-monitor
namespace: prometheus
labels:
monitoring: istio-components
release: prom
spec:
jobLabel: istio
targetLabels: [app]
selector:
matchExpressions:
- {key: istio, operator: In, values: [pilot]}
namespaceSelector:
any: true
endpoints:
- port: http-monitoring # 15014
interval: 15s
서비스 모니터를 추가하면 Prometheus UI에서 타겟 확인이 가능하고, Istio 관련 메트릭들이 수집되기 시작한다.
Prometheus에서 타겟 페이지에 추가된 항목들을 직접 볼 수 있다.
데이터 플레인 메트릭 수집 — PodMonitor로 워크로드 수집하기
데이터 플레인 메트릭 수집을 활성화하려면 PodMonitor 리소스를 사용해 istio-proxy 컨테이너가 포함된 모든 파드에서 메트릭을 수집하면
먼저, 워크로드 파드에 다음과 같은 어노테이션이 설정되어 있어야 한다.
Annotations:
prometheus.io/path: /stats/prometheus
prometheus.io/port: 15020
prometheus.io/scrape: true
이 설정은 Prometheus가 파드의 15020 포트에서 메트릭을 긁어가도록 한다.
PodMonitor 리소스 배포
#
kubectl describe pod -n istioinaction
...
Annotations: ...
prometheus.io/path: /stats/prometheus
prometheus.io/port: 15020
prometheus.io/scrape: true
#
cat ch7/pod-monitor-dp.yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: envoy-stats-monitor
namespace: prometheus
labels:
monitoring: istio-proxies
release: prom
spec:
selector:
matchExpressions:
- {key: istio-prometheus-ignore, operator: DoesNotExist}
namespaceSelector:
any: true
jobLabel: envoy-stats
podMetricsEndpoints:
- path: /stats/prometheus
interval: 15s
relabelings:
- action: keep
sourceLabels: [__meta_kubernetes_pod_container_name]
regex: "istio-proxy"
- action: keep
sourceLabels: [__meta_kubernetes_pod_annotationpresent_prometheus_io_scrape]
- sourceLabels: [
__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
targetLabel: __address__
- action: labeldrop
regex: "__meta_kubernetes_pod_label_(.+)"
- sourceLabels: [__meta_kubernetes_namespace]
action: replace
targetLabel: namespace
- sourceLabels: [__meta_kubernetes_pod_name]
action: replace
targetLabel: pod_name
# PodMonitor 설정 적용
kubectl apply -f ch7/pod-monitor-dp.yaml -n prometheus
#
kubectl get podmonitor -n prometheus
NAME AGE
envoy-stats-monitor 6s
메트릭이 잘 수집되는지 확인하려면 아래처럼 웹앱을 반복 호출한다.
# metric 확인을 위해서 호출테스트
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/ ; sleep 0.5; done
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
# 반복 접속
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
# 직접 파드에서 메트릭 조회
WEBAPP=$(kubectl get pod -n istioinaction -l app=webapp -o jsonpath='{.items[0].status.podIP}')
kubectl exec -it netshoot -- curl -s $WEBAPP:15020/stats/prometheus
...
kubectl exec -it netshoot -- curl -s $WEBAPP:15090/stats/prometheus
...
PodMonitor 적용 후 Prometheus에서 타겟 조회하면 Istio 데이터 플레인 워크로드(애플리케이션)가 수집 대상으로 표시된다.
이때 메트릭 개수가 3개로 나오는 경우는 어노테이션 prometheus.io/scrape가 적용된 워크로드가 3개이기 때문이다.
4. Istio 메트릭 커스터마이징
초반부에서 소개한 것처럼, 아래와 같이, Istio는 서비스 간 통신에서 기본적으로 여러 표준 메트릭을 활성화한다.
메트릭 | 설명 | |
---|---|---|
istio_requests_total | COUNTER, 요청이 들어올 때마다 증가 | |
istio_request_duration_milliseconds | DISTRIBUTION, 요청 지속 시간이 분포 | |
istio_request_bytes | DISTRIBUTION, 요청 바디 크기의 분포 | |
istio_response_bytes | DISTRIBUTION, 응답 바디 크기의 분포 | |
istio_request_messages_total | (gRPC) COUNTER, 클라이언트에게서 메시지가 올 때마다 증가 | |
istio_response_messages_total | (gRPC) COUNTER, 서버가 메시지를 보낼 때마다 증가 |
운영 환경에서는 이런 표준 메트릭을 단순히 쓰기보다는 , 플러그인을 통해 표시 방식, 커스터마이징, 생성 방식 등을 조절해야 할 때가 많다.
이를 이해하려면 세 가지 핵심 개념을 알아야 한다.
주요 개념 1 : 메트릭 (Metric)
메트릭은 서비스 호출 간의 telemetry 데이터를 수집해 저장하는 단위로, 주로 세 가지 타입으로 구분된다:
- Counter → 단순 카운트 (예: 요청 수)
- Gauge → 현재 상태 값 (예: 메모리 사용량)
- Histogram / Distribution → 값의 분포 (예: 요청 처리 시간)
주요 개념 2 - 디멘션 (Dimension)
- 디멘션은 메트릭의 메트릭을 잘게 나누는 기준이다.
- 예를 들어 동일한 istio_requests_total 메트릭도 요청의 소스(source), 대상(destination), 응답 코드(response_code), 프로토콜(protocol) 같은 디멘션 값에 따라 구분된다.
예를 들면, source, destination으로 메트릭을 나누어 hop별 상태를 구분해 문제를 좁힐 수도 있다.
- source: 요청을 보낸 프록시가 기록한 메트릭
- destination: 요청을 받은 프록시가 기록한 메트릭
주요 개념 3 - 속성(request attribute)
- 속성은 Envoy 프록시에서 추출할 수 있는 요청의 상세 정보다.
- 속성은 디멘션의 값으로 주로 사용되며, 기존 메트릭을 더 세부적으로 나누는 데 활용된다.
- 예를 들어, request.protocol 속성을 디멘션으로 추가하면 HTTP 요청과 gRPC 요청을 별도로 분리해서 볼 수 있다. 이런 커스터마이징은 운영 환경에서 메트릭을 좀 더 실용적으로 분류하고 분석할 수 있도록 돕는다.
- 자세한 속성은 해당 문서 참고 - 엔보이의 속성
속성 | 설명 |
---|---|
request.path | URL 중 경로 부분 |
request.url_parh | URL 중 경로 부분, 쿼리 문자열 제외 |
request.host | URL 중 호스트 부분 |
request.scheme | URL 중 스킴 부분(예: ‘http’) |
request.headers | 요청 메서드 (예. ‘GET’) |
request.referer | 요청 헤더 Referer |
request.useragent | 요청 헤더 User agent |
request.time | 첫 번째 바이트 수신 시간 |
request.id | x-request-id 헤더 값에 해당하는 요청 ID |
request.protocol | 요청 프로토콜 |
1. 기존 메트릭 수정 및 디멘션 추가
Istio의 표준 메트릭은 Istio 설치 시 함께 설치되는 EnvoyFilter 리소스로 구성되며, 이 안에서 stats 필터(wasm: WebAssembly 플러그인 기반) 를 사용해 메트릭 수집 방식을 정의한다. 쉽게 말해서, Envoy 프록시에 주입되는 istio.stats
필터가 메트릭 생성의 핵심이다.
기존 메트릭에 디멘션 추가하기
기본 메트릭에 추가로 디멘션(dimension)을 붙이면 어떤 상황에서, 어떤 조건에서 발생한 데이터인지 훨씬 세밀하게 구분할 수 있다
이런 디멘션들을 붙이면 메시 간 통신 문제 분석 시, 세부적으로 분석이 가능해진다. 반대로 request_protocol 같은 덜 중요한 디멘션은 제거해서 메트릭이 과부하 되는 것을 막을 수 있다.
- upstream_proxy_version: 업스트림 프록시의 Istio 버전
- source_mesh_id: 요청을 보낸 메시(mesh)의 ID
- request_protocol : 덜 중요한 디멘션 제거
IstioOperator 리소스의 telemetry.v2.prometheus.configOverride
항목에 inbound, outbound, gateway 별로 수집할 메트릭과 추가/제거할 디멘션 정의한다.
#
cat ch7/metrics/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
# 적용
istioctl install -f istio-operator-new-dimensions.yaml -y
Istio 1.16까지는 Deployment의 pod spec에 sidecar.istio.io/extraStatTags 애노테이션을 넣어, Envoy가 해당 디멘션을 인식하도록 설정해야 했다. Istio 1.17부터는 이 어노테이션 없이도 IstioOperator 설정만으로 커스텀이 가능해졌다.
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: |-
extraStatTags:
- "upstream_proxy_version"
- "source_mesh_id"
...
메트릭 확인
- request_protocol 디멘션이 디멘션 목록에 없는 것도 확인
- mesh_id, upsteram_proxy_version 확인
2. 새로운 메트릭 만들기(Creating New Metrics)
기존 Istio 메트릭으로는 부족할 때, stats 플러그인에 새 메트릭을 정의하면 된다. 이렇게 하면 운영 환경에서 특정 요청 패턴이나 비즈니스 이벤트를 직접 계측할 수 있어 더 맞춤화된 모니터링이 가능해진다.
새로운 메트릭을 만들려면 몇 가지 기본 개념을 먼저 이해할 필요가 있다.
먼저 메트릭 이름은, 예를 들어 getcalls라고 정의하면 Prometheus에서 자동으로 istio_get_calls라는 이름으로 표시된다. Istio는 모든 커스텀 메트릭 앞에 istio 접두사를 자동으로 붙이기 때문이다.
메트릭에는 세 가지 타입이 있다.
- COUNTER는 숫자가 계속 올라가기만 하는 타입으로, 예를 들어 요청 수를 셀 때 사용한다.
- GAUGE는 숫자가 올라갔다 내려갔다 할 수 있는 타입으로, 메모리 사용량처럼 변화하는 값을 나타낼 때 적합하다.
- 마지막으로 HISTOGRAM은 값의 분포를 볼 수 있는 타입인데, 예를 들어 요청 처리 시간이 얼마나 걸리는지를 측정할 때 쓴다.
이 메트릭들이 어떤 값을 기록할지는 CEL(Common Expression Language)이라는 간단한 계산식을 통해 정한다. 예를 들어 "(request.method.startsWith('GET') ? 1 : 0)"라는 식은 요청 메서드가 GET일 때 1을 반환하고, 그렇지 않으면 0을 반환한다. 이렇게 해서 GET 요청 개수를 카운트하는 메트릭을 만들 수 있는 것이다
예제 — GET 요청 카운트 메트릭 생성
다음 설정은 GET 요청 개수를 세는 istio_get_calls COUNTER 메트릭을 추가한다.
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
# 적용
istioctl verify-install -f istio-operator-new-metric.yaml # 리소스별로 적용결과를 출력
istioctl install -f istio-operator-new-metric.yaml -y
반복 호출하여 메트릭을 생성 테스트 한다.
# 호출테스트
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
Prometheus UI에서 istio_get_calls 메트릭을 검색하면 추가된 항목을 볼 수 있다.
이제 GET 요청별 카운트를 별도로 추적할 수 있으므로, 예를 들어 POST, PUT, DELETE 요청과의 비율이나 특정 클라이언트의 호출 패턴도 모니터링 가능하다.
3. 새 속성으로 호출 그룹화하기(Grouping calls with new attributes)
이번에는 기존 메트릭만으로는 부족할 때, 새로운 속성(attribute)을 만들어, 특정 종류의 API 호출을 구분하고 카운트하는 방법을 알아보자.
예를 들어, catalog 서비스의 /items API로 가는 GET 요청, POST 요청, DELETE 요청을 각각 따로 구분해서 보고 싶다고 해보자.
이를 위해 Istio에서는 attribute-gen 플러그인을 사용한다. -> 이 플러그인은 앞에서 쓴 stats 플러그인을 보완해 주는 역할을 한다.
attribute-gen 플러그인은 HTTP 요청의 path와 method를 조합해서 새로운 속성인 istio_operationId를 만든다.
- /items에 대한 GET → getitems
- /items에 대한 POST → createitem
- /items에 대한 DELETE → deleteitem
cat ch7/metrics/attribute-gen.yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: attribute-gen-example
namespace: istioinaction
spec:
configPatches:
## Sidecar Outbound
- applyTo: HTTP_FILTER
match:
context: SIDECAR_OUTBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: istio.stats
proxy:
proxyVersion: ^1\.13.*
patch:
operation: INSERT_BEFORE
value:
name: istio.attributegen
typed_config:
'@type': type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
configuration:
'@type': type.googleapis.com/google.protobuf.StringValue
value: |
{
"attributes": [
{
"output_attribute": "istio_operationId", # 속성 이름
"match": [
{
"value": "getitems", # 속성 값
"condition": "request.url_path == '/items' && request.method == 'GET'"
},
{
"value": "createitem",
"condition": "request.url_path == '/items' && request.method == 'POST'"
},
{
"value": "deleteitem",
"condition": "request.url_path == '/items' && request.method == 'DELETE'"
}
]
}
]
}
vm_config:
code:
local:
inline_string: envoy.wasm.attributegen
runtime: envoy.wasm.runtime.null
이렇게 하면 메트릭에서 단순히 “몇 번 요청했는가”가 아니라 “어떤 종류의 요청이 몇 번 발생했는가”까지 추적할 수 있다.
# metric 확인을 위해서 호출테스트
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done
istio_requests_total{upstream_operation!=""} 쿼리를 실행하면 이제 비어 있지 않은 upstream_operation 값들이 표시되며, GET, POST, DELETE 요청별 카운트를 확인할 수 있다
5. Grafana로 Istio 메트릭 시각화하기
이전 단계에서 kube-prometheus-stack을 설치할 때 Grafana도 함께 구성했다. Prometheus로 Istio 메트릭을 수집하고 있으니, 이제 Grafana에서 이 데이터를 대시보드로 시각화해 보자.
Istio용 Grafana 대시보드 설정하기
- 먼저 Istio에서 제공하는 여러 대시보드 JSON 파일을 ConfigMap으로 Kubernetes에 등록한다.
- 이 단계에서는 pilot, workload, service, performance, mesh, extension 대시보드를 포함한다.
cd ch8
kubectl -n prometheus create cm istio-dashboards \
--from-file=pilot-dashboard.json=dashboards/\
pilot-dashboard.json \
--from-file=istio-workload-dashboard.json=dashboards/\
istio-workload-dashboard.json \
--from-file=istio-service-dashboard.json=dashboards/\
istio-service-dashboard.json \
--from-file=istio-performance-dashboard.json=dashboards/\
istio-performance-dashboard.json \
--from-file=istio-mesh-dashboard.json=dashboards/\
istio-mesh-dashboard.json \
--from-file=istio-extension-dashboard.json=dashboards/\
istio-extension-dashboard.json
kubectl describe cm -n prometheus istio-dashboards
Grafana가 위 ConfigMap을 자동 인식하게 하려면 ConfigMap에 grafana_dashboard=1 라벨을 추가해줘야 한다.
# Grafana (오퍼레이터)가 configmap(istio-dashboards)을 마운트(인식) 하도록 레이블 지정
kubectl label -n prometheus cm istio-dashboards grafana_dashboard=1
Grafana에서 대시보드 확인하기
이제 컨트롤 플레인, 서비스, 워크로드, 성능, 메시 전체 상태 등 다양한 Istio 메트릭을 한눈에 볼 수 있게 된다
컨트롤 플레인 대시보드
Grafana에 들어가서 Istio Control Plane Dashboard를 선택하면, 앞에서 설정했던 ServiceMonitor 리소스 덕분에 컨트롤 플레인 메트릭들이 잘 수집되어 있는 걸 볼 수 있다.
이 대시보드에서는 단순히 CPU, 메모리, 고루틴(goroutines) 같은 시스템 리소스 정보뿐 아니라, 컨트롤 플레인에서 발생하는 오류, 설정 동기화 문제, 그리고 활성 데이터 플레인 연결 수 같은 운영에 중요한 데이터도 함께 확인할 수 있다
데이터 플레인 대시보드
Grafana에 들어가서 Istio Service Dashboard(데이터 플레인)를 선택하면, 앞에서 설정했던 PodMonitor 리소스 덕분에 webapp 같은 특정 서비스를 선택해서 해당 서비스의 메트릭을 볼 수 있다.
이 대시보드는 주로 Istio 표준 메트릭으로 구성돼 있어서, 서비스 간 요청 수, 지연 시간, 오류율 같은 핵심 지표들을 한눈에 확인할 수 있다.
6. Istio에서 분산 트레이싱(Jaeger) 적용하기
Istio에서의 분산 트레이싱
분산 트레이싱의 필요성
마이크로서비스가 많아질수록, 서비스 간 요청 경로에서 문제가 생겼을 때 “어디서, 무슨 일이, 왜” 일어나는지 파악하는 것이 점점 더 중요해진다. 이때 분산 트레이싱(distributed tracing) 이 큰 도움이 된다. 분산 트레이싱은 요청에 주석(annotation)을 달아 서비스 간의 관계와 요청 흐름을 추적할 수 있게 만든다.
예를 들어,
- correlation ID: 서비스 간 호출을 연결하는 ID
- trace ID: 요청 하나가 여러 서비스를 거쳐가는 전체 흐름을 식별하는 ID
Istio에서는 Jaeger나 Zipkin 같은 트레이싱 툴을 활용할 수 있고, 이때 주로 x-request-id
같은 HTTP 헤더에 이 ID 정보가 담긴다.
Istio에서의 분산 트레이싱 장점
보통 분산 트레이싱을 사용하려면, 개발자가 직접 애플리케이션 코드에 계측(Instrumentation)을 넣고, 서비스 간 호출에 주석을 붙여줘야 한다. 하지만 Istio를 사용하면, 사이드카(Envoy 프록시)가 이 작업을 대신해주기 때문에, 언어별 라이브러리나 애플리케이션 별 설정 없이 자동으로 스팬(span)을 수집하고 Jaeger 같은 분산 트레이싱 시스템으로 전송할 수 있다.
즉, Istio 덕분에 분산 트레이싱이 서비스 메시의 일부로 자연스럽게 들어오고, 개발자는 코드에 손을 거의 안 대고도 요청 흐름을 추적할 수 있다.
분산 트레이싱 시스템 설치하기(Jaeger)
Jaeger는 기본적으로 데이터를 저장할 DB가 필요해서 설치가 다소 복잡하다. 그래서 실습에서는 all-in-one 배포 샘플을 사용한다.
이 배포에는 Jaeger, Collector, Query, UI 등이 한 번에 포함돼 있어서 간편하다.
cat istio-$ISTIOV/samples/addons/jaeger.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
namespace: istio-system
labels:
app: jaeger
spec:
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
sidecar.istio.io/inject: "false"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "14269"
spec:
containers:
- name: jaeger
image: "docker.io/jaegertracing/all-in-one:1.35"
env:
- name: BADGER_EPHEMERAL
value: "false"
- name: SPAN_STORAGE_TYPE
value: "badger"
- name: BADGER_DIRECTORY_VALUE
value: "/badger/data"
- name: BADGER_DIRECTORY_KEY
value: "/badger/key"
- name: COLLECTOR_ZIPKIN_HOST_PORT
value: ":9411"
- name: MEMORY_MAX_TRACES
value: "50000"
- name: QUERY_BASE_PATH
value: /jaeger
livenessProbe:
httpGet:
path: /
port: 14269
...
kubectl apply -f istio-$ISTIOV/samples/addons/jaeger.yaml
Istio에서 분산 트레이싱 설정하기
Istio는 분산 트레이싱을 메시 전체, 네임스페이스 단위, 특정 워크로드 단위로 유연하게 설정할 수 있다.
이번 실습에서는 메시 전체와 워크로드 단위 설정을 다룬다.
설치 전에 트레이싱 백엔드 연결
Istio는 여러 분산 트레이싱 백엔드를 지원한다.
- Jaeger (Zipkin 호환)
- Zipkin
- Datadog
실습에서는 Zipkin이 호환되는 Jaeger로 백엔드를 설정한다.
# ch8/install-istio-tracing-zipkin.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
spec:
meshConfig:
defaultConfig:
tracing:
sampling: 100
zipkin:
address: zipkin.istio-system:9411
# 적용
istioctl install -y -f install-istio-tracing-zipkin.yaml
Istio의 기본 트레이싱 헤더 확인
httpbin.org라는 외부 HTTP 테스트 서비스로 요청을 보내 헤더에 Zipkin 트레이싱 정보가 잘 붙는지 확인한다.
Istio Ingress Gateway에 httpbin.istioinaction.io 도메인을 추가해, httpbin.org로 라우팅 되도록 VirtualService, Gateway, ServiceEntry를 설정한다.
#
cat ch8/tracing/thin-httpbin-virtualservice.yaml
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: coolstore-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "webapp.istioinaction.io"
- "httpbin.istioinaction.io"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: thin-httbin-virtualservice
spec:
hosts:
- "httpbin.istioinaction.io"
gateways:
- coolstore-gateway
http:
- route:
- destination:
host: httpbin.org
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-httpbin-org
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
location: MESH_EXTERNAL
resolution: DNS
#
kubectl apply -n istioinaction -f ch8/tracing/thin-httpbin-virtualservice.yaml
# 확인
kubectl get gw,vs,serviceentry -n istioinaction
# 도메인 질의를 위한 임시 설정 : 실습 완료 후에는 삭제 해둘 것
echo "127.0.0.1 httpbin.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 5
/headers 엔드포인트로 요청을 보내면, 요청 헤더가 그대로 응답에 출력된다.(httbin)
여기서 Istio가 자동으로 주입한 x-b3-* 헤더들을 확인할 수 있다.
Istio는 코드 수정 없이 트레이싱 헤더를 자동으로 붙인다. 이 헤더들은 각 서비스로 전달되어 스팬 생성에 쓰이고, 최종적으로 Jaeger로 전송된다.
메시의 트레이스 샘플링 비율 조정하기
분산 트레이싱은 요청마다 스팬(span) 정보를 수집해서 Jaeger 같은 시스템으로 보내는데, 이 작업은 시스템 성능에 꽤 부담을 줄 수 있다.
그래서 서비스가 정상적으로 운영될 때는 샘플링 비율을 낮춰서, 전체 요청 중 일부만 트레이싱하도록 설정하는 게 좋다.
예를 들어, 샘플링 비율을 10%로 설정하면 전체 요청 중 10%만 트레이스에 기록된다.
메시 전역 샘플링 비율 변경
Istio의 전역 샘플링 설정은 ConfigMap에서 조정할 수 있다.
이렇게 하면 메시 안의 모든 워크로드에 대해 샘플링 비율이 10%로 전역 적용된다.
# 샘플링 적용은 istio-ingressgateway 재배포 필요 참고.
kubectl rollout restart deploy -n istio-system istio-ingressgateway
전역 설정 대신, 특정 워크로드만 따로 조정할 수도 있다. Deployment의 파드 템플릿에 애노테이션을 추가해서 지정하면 된다.
#
cat ch8/webapp-deployment-zipkin.yaml
...
selector:
matchLabels:
app: webapp
template:
metadata:
annotations:
proxy.istio.io/config: |
tracing:
sampling: 10 # 퍼센트 직접 수정 후 적용 해보세요!
zipkin:
address: zipkin.istio-system:9411
클라이언트에서 트레이싱 강제하기(강제 트레이스)
운영 환경에서는 보통 트레이싱 샘플링 비율을 매우 낮게 설정한다. 예를 들어 1%만 트레이싱하면 성능 부담은 줄지만, 문제가 생겼을 때는 “딱 그 문제 요청”이 기록되지 않을 위험이 있다. 이럴 때 특정 요청에 대해서만 트레이싱을 강제로 켜는 방법이 유용하다.
Istio에서 강제 트레이스하는 방법
Istio는 x-envoy-force-trace
라는 HTTP 헤더를 지원한다. 이 헤더를 요청에 포함하면 샘플링 설정과 상관없이 그 요청은 무조건 트레이싱된다.
이렇게 하면 webapp 서비스로 가는 해당 요청은 강제로 트레이싱되고, Jaeger 같은 트레이싱 백엔드에 기록된다.
# 3번 호출하여 Jaeger에서 확인!
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
...
트레이스의 태그 커스터마이징하기(커스텀 태그)
분산 트레이싱에서 스팬(span) 안에 추가할 수 있는 정보 중 하나가 태그(tag)다. 태그는 말 그대로 간단한 키-값 쌍으로, 애플리케이션이나 조직에서 중요한 메타데이터를 트레이스에 첨부할 때 사용한다. 예를 들어, 서비스 이름, 버전, 사용자 ID, 실험 그룹 같은 것들을 태그로 붙일 수 있으며, Jaeger나 Zipkin 같은 트레이싱 도구에서 , 필터링, 탐색하기가 쉬워진다.
webapp 서비스에 커스텀 태그 적용
환경 변수(파드)에서 값을 가져오거나, 요청 헤더에서도 값을 추출하여 태그를 설정할 수도 있다고 한다. 실습 테스트에서는 Test Tag 라는 고정된 값으로 설정한다.
cat ch8/webapp-deployment-zipkin-tag.yaml
...
template:
metadata:
annotations:
proxy.istio.io/config: |
tracing:
sampling: 100
customTags:
custom_tag: # 커스텀 태그의 키
literal:
value: "Test Tag" # 커스텀 태그의 값
zipkin:
address: zipkin.istio-system:9411
...
# webapp 에 커스텀 태그 적용
kubectl apply -n istioinaction -f ch8/webapp-deployment-zipkin-tag.yaml
백엔드 분산 트레이싱 엔진 커스터마이징하기
지금까지의 예제에서는 Istio에서 Jaeger나 Zipkin 같은 분산 트레이싱 백엔드로 데이터를 보낼 때, 대체로 호스트 이름과 포트만 지정하면 충분했다(zipkin.istio-system:9411). 그런데, 때로는 이보다 더 세부 설정을 조정해야 할 때가 있다.
Jaeger의 Zipkin 호환 엔드포인트 커스터마이징
잘못된 정보로 엔드포인트를 커스터마이징하여, 엔드포인트 커스터마이징이 잘되는지 확인해 보자.
- collectorEndpoint를 /api/v2/spans로 보내야 하는데
- 잘못해서 /zipkin/api/v1/spans 같은 잘못된 경로로 보내면
- Jaeger 대시보드에서 Span 데이터가 안 뜨게 된다.
이럴 때는 ConfigMap을 만들어 Envoy Proxy의 부트스트랩 설정(bootstrap config)을 덮어쓴다.
# 해당 configmap 은 collectorEndpoint 를 변경한 설정 스니펫
cat ch8/istio-custom-bootstrap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: istio-custom-zipkin
data:
custom_bootstrap.json: |
{
"tracing": {
"http": {
"name": "envoy.tracers.zipkin",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
"collectorCluster": "zipkin",
"collectorEndpoint": "/zipkin/api/v1/spans",
"traceId128bit": "true",
"collectorEndpointVersion": "HTTP_JSON" # 잘못된 경로 예시
}
}
}
}
# 이 부트스트랩 설정을 덮어 쓰려는 워크로드가 있는 네임스페이스에 configmap 을 적용할 수 있다.
kubectl apply -n istioinaction -f ch8/istio-custom-bootstrap.yaml
Istio Proxy의 부트스트랩 설정 확인
이때 경로나 버전 설정을 잘못하면 → 데이터 누락 → Jaeger UI에서 webapp의 Span이 안 보인다.
7. Kiali로 Istio 시각화하기
Kiali는 오픈소스 시각화 툴로, istio 전용 시각화 툴이라고 할 정도로 서비스 메시 내부에서 서비스들이 어떻게 연결되고, 통신하고 있는지를 실시간 그래프로 보여줘서, 메시 상황을 한눈에 파악할 수 있게 도와준다.
키알리 설치하기(Kiali Operator )
프로메테우스나 그라파나와 마찬가지로 이스티오는 키알리 샘플 버전을 기본적으로 제공하지만, 운영 시, kiali를 독립적으로 설치하는 것을 권장한다. 공식문서에서는 키알리 오퍼레이터를 사용하기를 권장하므로 해당 방식으로 설치한다.
Kiali Operator 설치
# helm repo
helm repo add kiali https://kiali.org/helm-charts
helm repo update
# kiali-operator install : 책은 1.40.1
helm install --namespace kiali-operator --create-namespace --version 1.63.2 kiali-operator kiali/kiali-operator
# kiali-operator 확인
kubectl get pod -n kiali-operator
NAME READY STATUS RESTARTS AGE
kiali-operator-584858fb7-w5p2q 1/1 Running 0 60s
Kiali 인스턴스 배포
cat ch8/kiali.yaml
apiVersion: kiali.io/v1alpha1
kind: Kiali
metadata:
namespace: istio-system
name: kiali
spec:
istio_namespace: "istio-system"
istio_component_namespaces:
prometheus: prometheus
auth:
strategy: anonymous # 익명 접근 허용
deployment:
accessible_namespaces:
- '**'
external_services:
prometheus: # 클러스터 내에서 실행 중인 프로메테우스 설정
cache_duration: 10
cache_enabled: true
cache_expiration: 300
url: "http://prom-kube-prometheus-stack-prometheus.prometheus:9090"
tracing: # 클러스터 내에서 실행 중인 예거 설정
enabled: true
in_cluster_url: "http://tracing.istio-system:16685/jaeger"
use_grpc: true
트래픽 확인을 위해서 반복 호출
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done
Kiali 살펴보기
Overview dashboard
네임스페이스별 서비스/워크로드 개수를 요약해서 보여줌
Graph 메뉴
- 서비스 메시 트래픽을 방향 그래프로 시각화
- 트래픽 양, 요청 성공률, 버전별 분포, 상태, HTTP/TCP 흐름, 네트워크 문제 등 실시간 표시
Workloads 메뉴
- Overview → 파드, 적용된 Istio 설정, 업스트림/다운스트림 연결 그래프
- Traffic → 인바운드/아웃바운드 요청 성공률
- Logs → 애플리케이션 로그 + Envoy 액세스 로그 + Jaeger 트레이스
- Traces → Jaeger에서 수집된 트레이스
- Envoy → Envoy에 적용된 클러스터, 리스너, 라우트 설정
8. 결론
Istio는 서비스 메시 환경에서 메트릭 수집, 분산 트레이싱, 시각화까지 강력한 관찰(Observability) 기능을 기본으로 제공한다.
Prometheus와 Grafana로 세부 지표를 모니터링하고, Jaeger로 트레이스 흐름을 파악하며, Kiali로 실시간 트래픽 구조를 한눈에 확인할 수 있다. 이 덕분에 개발자는 애플리케이션에 별도 코드를 추가하지 않고도, 안정적이고 투명한 운영 환경을 만들 수 있다.
'Kubernetes > Istio' 카테고리의 다른 글
Istio 시리즈 # 5 – 네트워크 복원력 강화하기(Resilience) (0) | 2025.04.27 |
---|---|
Istio 시리즈 # 4 – 세밀하게 트래픽 제어하기(Traffic Control) (0) | 2025.04.27 |
Istio 시리즈 # 3 – 외부 트래픽 진입점, Ingress Gateway 알아보기 (0) | 2025.04.20 |
Istio 시리즈 # 2 - Istio의 핵심, Envoy Proxy를 이해하자 (0) | 2025.04.20 |
Istio 시리즈 # 1 - 설치부터 기본 트레픽 제어까지 (0) | 2025.04.13 |