Istio 메트릭
지원 버전: Istio 1.31 마지막 업데이트: 2026년 9월 11일
검증 범위: 실습 설정은 공식 자료와 오프라인 검증기로 확인했으며 클러스터에 배포해 실행하지 않았습니다. 각 예제의 네임스페이스·신원·스토리지·백엔드·부하 전제 조건은 대상 환경에서 확인해야 합니다.
Istio 프록시는 관측한 트래픽의 메트릭을 생성합니다. 이 문서는 사이드카/Envoy의 HTTP·TCP 메트릭과 Prometheus 또는 OpenTelemetry Collector 스크레이프를 다룹니다. Ambient ztunnel은 별도 L4 메트릭을 사용하며 HTTP 메트릭에는 waypoint가 필요합니다.
목차
- 메트릭 개요
- Istio 표준 메트릭
- Circuit Breaker 메트릭
- Resilience 메트릭
- OpenTelemetry 통합
- Prometheus 통합
- Telemetry API를 통한 커스터마이징
- 실전 메트릭 쿼리
- 메트릭 최적화
- 문제 해결
메트릭 개요
Golden Signals
프록시 텔레메트리와 노드·컨테이너 exporter를 함께 사용해 Golden Signals를 측정합니다:
- Latency (지연시간): 요청 처리 시간
- Traffic (트래픽): 시스템 처리량 (RPS, Bandwidth)
- Errors (에러): 실패율과 에러 유형
- Saturation (포화도): 대기열·연결 압력과 Kubernetes exporter의 CPU·메모리
메트릭 수집 아키텍처
Envoy가 Prometheus 메트릭 노출 → Prometheus가 직접 스크레이프하거나 OpenTelemetry Collector의 Prometheus receiver가 스크레이프 → 설정한 메트릭 백엔드 → Grafana/Kiali. Istio OpenTelemetry extension provider는 추적을 구성하며 OTLP 메트릭 송신기가 아닙니다.
Istio 표준 메트릭
HTTP/gRPC 메트릭
Envoy는 HTTP/gRPC로 인식한 트래픽에 아래 메트릭을 생성합니다. 프록시별 관측이므로 목적에 맞는 reporter를 선택합니다. 수신 reporter는 같은 홉의 중복 집계를 피하고, 대상에 도달하지 못한 upstream 오류는 송신 reporter가 필요합니다. 서비스 이름은 네임스페이스(필요 시 클러스터)와 함께 그룹화합니다.
istio_requests_total
타입: Counter 설명: 처리된 총 요청 수
istio_requests_total{
reporter="destination", # Peer security policy populated at destination
source_workload="productpage-v1",
source_workload_namespace="default",
source_principal="spiffe://cluster.local/ns/default/sa/bookinfo-productpage",
source_app="productpage",
source_version="v1",
source_canonical_service="productpage",
source_canonical_revision="v1",
destination_workload="reviews-v1",
destination_workload_namespace="default",
destination_principal="spiffe://cluster.local/ns/default/sa/bookinfo-reviews",
destination_app="reviews",
destination_version="v1",
destination_service="reviews.default.svc.cluster.local",
destination_service_name="reviews",
destination_service_namespace="default",
destination_canonical_service="reviews",
destination_canonical_revision="v1",
request_protocol="http",
response_code="200",
response_flags="-",
connection_security_policy="mutual_tls",
grpc_response_status="",
destination_cluster="",
source_cluster=""
}주요 레이블:
response_code: HTTP 상태 코드 (200, 404, 500, etc.)response_flags: Envoy 응답 플래그UH: No healthy upstreamUF: Upstream connection failureUR: Upstream remote reset;UT: upstream request timeoutDC: Downstream connection terminationLR: Local resetURX: Upstream retry limit exceeded (or TCP maximum connect attempts)
connection_security_policy: mTLS 여부 (mutual_tls,none; source reports can beunknown)
istio_request_duration_milliseconds
타입: Histogram 설명: 요청 처리 시간 (밀리초)
istio_request_duration_milliseconds_bucket{le="10"} # 10ms 이하
istio_request_duration_milliseconds_bucket{le="50"} # 50ms 이하
istio_request_duration_milliseconds_bucket{le="100"} # 100ms 이하
istio_request_duration_milliseconds_bucket{le="500"} # 500ms 이하
istio_request_duration_milliseconds_sum # 총 시간
istio_request_duration_milliseconds_count # 총 요청 수istio_request_bytes
타입: Histogram 설명: 요청 본문 크기 (바이트)
istio_request_bytes_bucket # 실제 le 경계를 확인
istio_request_bytes_bucket{le="+Inf"} # 모든 본문 크기
istio_request_bytes_sum
istio_request_bytes_countistio_response_bytes
타입: Histogram 설명: 응답 본문 크기 (바이트)
istio_response_bytes_bucket
istio_response_bytes_bucket{le="+Inf"}
istio_response_bytes_sum
istio_response_bytes_countTCP 메트릭
istio_tcp_connections_opened_total
타입: Counter 설명: 열린 TCP 연결 수
istio_tcp_connections_opened_total{
reporter="source",
source_workload="mongodb-v1",
destination_service="mongodb.default.svc.cluster.local"
}istio_tcp_connections_closed_total
타입: Counter 설명: 닫힌 TCP 연결 수
istio_tcp_sent_bytes_total
타입: Counter 설명: 전송한 바이트 수
istio_tcp_received_bytes_total
타입: Counter 설명: 수신한 바이트 수
Circuit Breaker 메트릭
스크레이프 전에 proxyStatsMatcher로 필요한 Envoy 통계를 활성화합니다. 기본 Istio bootstrap은 cluster_name을 추출하며 사용자 bootstrap은 레이블이 다를 수 있습니다. Circuit breaker _open 메트릭은 이벤트 카운터가 아닌 0/1 gauge입니다. 일부 카운터는 트래픽 발생 후에만 보입니다.
주요 Circuit Breaker 메트릭
1. Upstream Connection Pool Overflow
# 연결 풀 오버플로우로 거부된 요청
envoy_cluster_upstream_cx_overflow{
cluster_name="outbound|80||httpbin.default.svc.cluster.local"
}의미: maxConnections 제한 초과
2. Circuit Breaker Open (Gauge)
# Gauge: 한도 도달 시 1, 한도 미만 0
envoy_cluster_circuit_breakers_default_rq_open{
cluster_name="outbound|80||httpbin.default.svc.cluster.local"
}3. Pending Requests Overflow
# 대기 중인 요청 수 초과
envoy_cluster_upstream_rq_pending_overflow{
cluster_name="outbound|80||httpbin.default.svc.cluster.local"
}의미: 대기·활성 요청 circuit breaker의 거부입니다. rq_pending_open, rq_open과 생성된 임계치로 대기열 압력과 활성 요청 제한을 구분합니다.
4. Retry Budget Exhausted
# 재시도 예산 소진
envoy_cluster_upstream_rq_retry_overflow{
cluster_name="outbound|80||httpbin.default.svc.cluster.local"
}5. Response Flags로 Circuit Breaker 감지
# Circuit Breaker로 거부된 요청 (response_flags="UO")
sum(rate(istio_requests_total{reporter="source",
response_flags=~".*UO.*",
destination_service="httpbin.default.svc.cluster.local"
}[5m]))Response Flags 상세:
UO: Upstream overflow (circuit breaker open)URX: Upstream retry limit exceeded (or TCP maximum connect attempts)UF: Upstream connection failureUH: No healthy upstream
Circuit Breaker 모니터링 대시보드 쿼리
# Fraction of observed samples at capacity over five minutes (%).
100 * avg_over_time(envoy_cluster_circuit_breakers_default_rq_open[5m])
# Active connections and pending requests (per proxy/cluster).
envoy_cluster_upstream_cx_active
envoy_cluster_upstream_rq_pending_active
# Rejected request events over five minutes.
sum by (namespace, pod, cluster_name) (
increase(envoy_cluster_upstream_rq_pending_overflow[5m])
)표준 circuit_breakers_default_cx_max·rq_pending_max gauge는 없습니다. 제한 값은 생성된 클러스터 설정에서 확인합니다. 선택적 remaining_cx·remaining_pending은 Envoy track_remaining이 필요하며 통계 이름을 포함하는 것만으로 활성화되지 않습니다. 사용률 분모는 일치하는 실제 설정 한도여야 합니다.
Circuit Breaker 알림 규칙
groups:
- name: istio_circuit_breaker
rules:
- alert: CircuitBreakerAtCapacity
expr: envoy_cluster_circuit_breakers_default_rq_open == 1
for: 1m
labels:
severity: warning
annotations:
summary: Request breaker remains at capacity for {{ $labels.cluster_name }}
- alert: ConnectionPoolOverflow
expr: rate(envoy_cluster_upstream_cx_overflow[5m]) > 0
for: 2m
labels:
severity: warning
annotations:
summary: Connection limit exceeded for {{ $labels.cluster_name }}
- alert: PendingRequestsOverflow
expr: rate(envoy_cluster_upstream_rq_pending_overflow[5m]) > 0
for: 2m
labels:
severity: warning
annotations:
summary: Request circuit-breaking rejection for {{ $labels.cluster_name }}Resilience 메트릭
Outlier Detection 메트릭
1. Ejected Hosts
# Outlier Detection으로 제거된 호스트 수
envoy_cluster_outlier_detection_ejections_active{
cluster_name="outbound|80||httpbin.default.svc.cluster.local"
}2. Ejection Events
# 제거 이벤트 발생률
rate(envoy_cluster_outlier_detection_ejections_enforced_total[5m])제거 유형별:
# Consecutive 5xx errors
envoy_cluster_outlier_detection_ejections_enforced_consecutive_5xx
# Success rate based
envoy_cluster_outlier_detection_ejections_enforced_success_rate
# Failure percentage based
envoy_cluster_outlier_detection_ejections_enforced_failure_percentage감지와 실제 ejection은 다릅니다. 감지된 outlier도 enforcement 확률·최대 ejection 비율 때문에 제외되지 않을 수 있습니다. 일부 Envoy 알고리즘은 Istio DestinationRule에 노출되지 않으므로 시계열 누락을 해당 알고리즘의 정상 상태로 해석하지 않습니다.
Retry 메트릭
# 재시도된 요청 수
rate(envoy_cluster_upstream_rq_retry[5m])
# 재시도 성공률
rate(envoy_cluster_upstream_rq_retry_success[5m])
/
rate(envoy_cluster_upstream_rq_retry[5m])
# 재시도 예산 소진
rate(envoy_cluster_upstream_rq_retry_overflow[5m])Timeout 메트릭
# 타임아웃 발생 요청
sum(rate(istio_requests_total{reporter="source",
response_flags=~".*UT.*"
}[5m])) by (destination_service)
# 타임아웃률
sum(rate(istio_requests_total{reporter="source",response_flags=~".*UT.*"}[5m]))
/
sum(rate(istio_requests_total{reporter="source"}[5m]))
* 100OpenTelemetry 통합
Istio 메트릭용 Prometheus Receiver
Istio opentelemetry extension provider는 트레이스를 내보냅니다. 표준 메시 메트릭은 Prometheus metrics provider를 유지하고 OpenTelemetry Collector의 Prometheus receiver로 노출 endpoint를 스크레이프합니다. Collector는 이후 OTLP로 메트릭 지원 백엔드에 내보낼 수 있습니다. Tempo는 트레이스 백엔드이며 메트릭 목적지가 아닙니다.
아래는 Collector Contrib 0.160.0의 Prometheus exporter로 결과를 조회하는 예제입니다. 먼저 observability 네임스페이스를 생성합니다. 동일 설정의 복제본은 모든 대상을 중복 수집하므로 replica는 1이며 운영 확장에는 대상 할당·샤딩이 필요합니다. ServiceAccount에는 파드 검색에 필요한 읽기 권한만 부여합니다. 평문 프록시 메트릭 15090·istiod 15014에 네트워크 접근을 구성하며 애플리케이션 메트릭·ambient ztunnel은 이 예제의 수집 대상이 아닙니다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: otel-metrics
namespace: observability
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: otel-metrics-pod-reader
rules:
- apiGroups:
- ''
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: otel-metrics-pod-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: otel-metrics-pod-reader
subjects:
- kind: ServiceAccount
name: otel-metrics
namespace: observability
---
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-metrics-config
namespace: observability
data:
config.yaml: |
receivers:
prometheus:
config:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: envoy-stats
metrics_path: /stats/prometheus
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_phase
action: keep
regex: Running
- source_labels:
- __meta_kubernetes_pod_container_name
- __meta_kubernetes_pod_container_port_name
action: keep
regex: istio-proxy;.*-envoy-prom
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
- job_name: istiod
metrics_path: /metrics
kubernetes_sd_configs:
- role: pod
namespaces:
names:
- istio-system
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_label_app
- __meta_kubernetes_pod_container_port_name
action: keep
regex: istiod;http-monitoring
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
processors:
memory_limiter:
check_interval: 1s
limit_mib: 512
batch:
timeout: 10s
send_batch_size: 1024
exporters:
prometheus:
endpoint: 0.0.0.0:8889
const_labels:
environment: production
debug:
verbosity: basic
service:
pipelines:
metrics:
receivers:
- prometheus
processors:
- memory_limiter
- batch
exporters:
- prometheus
- debug
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-metrics
namespace: observability
spec:
replicas: 1
selector:
matchLabels:
app: otel-metrics
template:
metadata:
labels:
app: otel-metrics
annotations:
sidecar.istio.io/inject: 'false'
spec:
serviceAccountName: otel-metrics
containers:
- name: otel-collector
image: otel/opentelemetry-collector-contrib:0.160.0
args:
- --config=/etc/otel/config.yaml
ports:
- containerPort: 8889
name: prometheus
volumeMounts:
- name: config
mountPath: /etc/otel
readOnly: true
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
volumes:
- name: config
configMap:
name: otel-metrics-config
---
apiVersion: v1
kind: Service
metadata:
name: otel-metrics
namespace: observability
labels:
app: otel-metrics
spec:
selector:
app: otel-metrics
ports:
- name: prometheus
port: 8889
targetPort: prometheus제거된 logging exporter 대신 debug를 사용하며 검증 후 진단 출력은 제거합니다. 기존 메트릭 이름에 istio_가 중복되지 않도록 namespace: istio 접두사를 추가하지 않습니다. Kiali 대시보드 재사용 전에 실제 출력 레이블·이름을 확인합니다. Prometheus Operator를 사용하면 레이블이 지정된 Service를 선택합니다:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: otel-metrics
namespace: observability
spec:
selector:
matchLabels:
app: otel-metrics
endpoints:
- port: prometheus
interval: 15s
path: /metrics
honorLabels: truePrometheus 리소스가 이 ServiceMonitor와 네임스페이스를 선택해야 합니다. honorLabels는 원본 target의 job/instance를 유지하므로 collector를 신뢰할 수 있어야 합니다. 같은 시계열에는 이 경로와 아래 직접 프록시 스크레이프 중 하나를 사용합니다. ServiceMonitor는 Prometheus를 설치하지 않습니다.
수집 검증
kubectl logs -n observability deployment/otel-metrics
# Keep this running in one terminal.
kubectl port-forward -n observability svc/otel-metrics 8889:8889# In a second terminal, after generating test mesh traffic:
curl -fsS http://localhost:8889/metrics | rg '^istio_'트레이스 OTLP receiver·exporter는 추적 장에서 별도로 구성합니다. 프록시 debug 로그만으로 메트릭 전달을 증명할 수는 없습니다.
Prometheus 통합
Prometheus 설정
다음 설정을 파드 list/watch 권한이 있는 설치된 Prometheus 서버에 적용합니다. ConfigMap만으로 Prometheus가 배포·재로드되지는 않습니다. 파드 검색 주소(IPv6 포함)를 유지하며 Envoy 메트릭 포트 또는 istiod monitoring 포트만 선택합니다. 사이드카·게이트웨이를 함께 포함하므로 별도 gateway job은 중복 수집을 만듭니다. 제거된 Mixer istio-telemetry Service는 대상이 아닙니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: istio-system
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: envoy-stats
metrics_path: /stats/prometheus
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_phase
action: keep
regex: Running
- source_labels:
- __meta_kubernetes_pod_container_name
- __meta_kubernetes_pod_container_port_name
action: keep
regex: istio-proxy;.*-envoy-prom
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
- job_name: istiod
metrics_path: /metrics
kubernetes_sd_configs:
- role: pod
namespaces:
names:
- istio-system
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_label_app
- __meta_kubernetes_pod_container_port_name
action: keep
regex: istiod;http-monitoring
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod프록시 전용 수집은 15090 /stats/prometheus를 사용합니다. 기본 agent·애플리케이션 병합 메트릭은 prometheus.io annotation 기반 15020 /stats/prometheus를 사용하므로 중복되지 않는 별도 job이 필요합니다. Agent 인증서 메트릭에는 agent endpoint가 필요합니다. 애플리케이션이 STRICT mTLS여도 이 메트릭 listener는 평문이므로 네트워크 노출을 제한합니다. 별도 애플리케이션 endpoint는 해당 인증 정책을 따릅니다.
Prometheus Operator 대안
수동 job 대신 다음을 사용하고 Prometheus 리소스가 레이블·네임스페이스를 선택하도록 합니다. namespaceSelector.any: true는 애플리케이션 네임스페이스도 검색하고 port: http-envoy-prom은 실제 메트릭 컨테이너 포트를 선택합니다. 사용자 gateway 포트 이름은 맞춰야 합니다. ServiceMonitor는 Deployment 레이블이 아닌 Service를 선택합니다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istio-component-monitor
namespace: istio-system
spec:
selector:
matchLabels:
app: istiod
endpoints:
- port: http-monitoring
interval: 15s
path: /metrics
---
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: envoy-stats-monitor
namespace: istio-system
spec:
namespaceSelector:
any: true
selector:
matchExpressions:
- key: istio-prometheus-ignore
operator: DoesNotExist
podMetricsEndpoints:
- port: http-envoy-prom
path: /stats/prometheus
interval: 15s
relabelings:
- sourceLabels:
- __meta_kubernetes_pod_container_name
action: keep
regex: istio-proxyPrometheus 쿼리 최적화
# Recording Rules로 자주 사용하는 쿼리 사전 계산
groups:
- name: istio_recording_rules
interval: 30s
rules:
# 서비스별 요청률
- record: istio:service:request_rate:5m
expr: |
sum(rate(istio_requests_total{reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
# 서비스별 에러율
- record: istio:service:error_rate:5m
expr: |
sum(rate(istio_requests_total{reporter="destination",response_code=~"5.."}[5m])) by (destination_service_name, destination_service_namespace)
/
sum(rate(istio_requests_total{reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
# 서비스별 P95 지연시간
- record: istio:service:latency_p95:5m
expr: |
histogram_quantile(0.95,
sum(rate(istio_request_duration_milliseconds_bucket{reporter="destination"}[5m]))
by (destination_service_name, destination_service_namespace, le)
)
# Circuit Breaker 상태 gauge
- record: istio:circuit_breaker:at_capacity
expr: |
envoy_cluster_circuit_breakers_default_rq_openTelemetry API를 통한 커스터마이징
메트릭 커스터마이징
1. 특정 메트릭만 활성화
Override는 순서대로 적용됩니다. ALL_METRICS를 끈 뒤 필요한 두 HTTP 메트릭을 켭니다. mode는 match 내부 필드입니다. 아래 독립 예제를 모두 함께 적용하지 말고 선택 범위별 하나의 Telemetry에 필요한 설정을 병합합니다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: custom-metrics
namespace: istio-system
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: ALL_METRICS
mode: CLIENT_AND_SERVER
disabled: true
- match:
metric: REQUEST_COUNT
mode: CLIENT_AND_SERVER
disabled: false
- match:
metric: REQUEST_DURATION
mode: CLIENT_AND_SERVER
disabled: false2. 커스텀 레이블 추가
HTTP 메트릭에는 값이 제한된 CEL 표현식을 사용합니다. 요청 ID·임의 User-Agent·타이밍 헤더는 레이블 수를 폭증시킵니다. x-envoy-upstream-service-time은 upstream 클러스터 신원이 아닌 시간이며 CEL은 예전 셸 형태의 | split() 문법을 사용하지 않습니다.
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: custom-tags
namespace: prod
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
api_version:
value: 'request.url_path.startsWith("/api/v1/") ? "v1" : (request.url_path.startsWith("/api/v2/")
? "v2" : "other")'
request_method:
value: 'request.method in ["GET", "POST", "PUT", "DELETE"] ? request.method
: "OTHER"'3. 네임스페이스별 메트릭 설정
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: namespace-metrics
namespace: production
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT_AND_SERVER
tagOverrides:
environment:
value: '"production"'4. 메트릭 비활성화로 성능 향상
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: disable-tcp-metrics
namespace: istio-system
spec:
metrics:
- providers:
- name: prometheus
overrides:
# TCP 메트릭 완전 비활성화
- match:
metric: TCP_OPENED_CONNECTIONS
disabled: true
- match:
metric: TCP_CLOSED_CONNECTIONS
disabled: true
- match:
metric: TCP_SENT_BYTES
disabled: true
- match:
metric: TCP_RECEIVED_BYTES
disabled: true실전 메트릭 쿼리
HTTP 상태 기반 에러율은 모든 gRPC 실패를 포착하지 않습니다. gRPC는 grpc_response_status와 애플리케이션의 실패 정의를 확인해야 하며 HTTP 200에도 0이 아닌 gRPC 상태가 포함될 수 있습니다.
Golden Signals 대시보드
1. Latency (지연시간)
# P50 지연시간
histogram_quantile(0.50,
sum(rate(istio_request_duration_milliseconds_bucket{reporter="destination",
destination_service_name="reviews", destination_service_namespace="default"
}[5m])) by (le)
)
# P95 지연시간
histogram_quantile(0.95,
sum(rate(istio_request_duration_milliseconds_bucket{reporter="destination",
destination_service_name="reviews", destination_service_namespace="default"
}[5m])) by (le)
)
# P99 지연시간
histogram_quantile(0.99,
sum(rate(istio_request_duration_milliseconds_bucket{reporter="destination",
destination_service_name="reviews", destination_service_namespace="default"
}[5m])) by (le)
)
# 서비스별 평균 지연시간
sum(rate(istio_request_duration_milliseconds_sum{reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
/
sum(rate(istio_request_duration_milliseconds_count{reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)2. Traffic (트래픽)
# 서비스별 요청률 (RPS)
sum(rate(istio_requests_total{reporter="destination"}[1m])) by (destination_service_name, destination_service_namespace)
# 총 요청률
sum(rate(istio_requests_total{reporter="destination"}[1m]))
# 서비스별 인바운드 트래픽 (bytes/sec)
sum(rate(istio_request_bytes_sum{reporter="destination"}[1m])) by (destination_service_name, destination_service_namespace)
# 서비스별 아웃바운드 트래픽 (bytes/sec)
sum(rate(istio_response_bytes_sum{reporter="destination"}[1m])) by (destination_service_name, destination_service_namespace)
# 프로토콜별 요청 분포(HTTP 메서드가 아님)
sum(rate(istio_requests_total{reporter="destination"}[5m])) by (request_protocol, destination_service_name, destination_service_namespace)3. Errors (에러)
# 에러율 (5xx errors)
sum(rate(istio_requests_total{response_code=~"5..", reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
/
sum(rate(istio_requests_total{reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
* 100
# 4xx vs 5xx 분리
sum(rate(istio_requests_total{response_code=~"4..", reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
sum(rate(istio_requests_total{response_code=~"5..", reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
# 특정 에러 코드 추적
sum(rate(istio_requests_total{response_code="503", reporter="destination"}[5m])) by (destination_service_name, destination_service_namespace)
# Response flags로 에러 유형 분석
sum(rate(istio_requests_total{response_flags!~"-", reporter="destination"}[5m])) by (response_flags, destination_service_name, destination_service_namespace)4. Saturation (포화도)
# Connection count and breaker state (not a utilization percentage).
envoy_cluster_upstream_cx_active
envoy_cluster_circuit_breakers_default_cx_open
# Active and pending requests.
envoy_cluster_upstream_rq_active
envoy_cluster_upstream_rq_pending_active
# Allocated proxy memory in bytes; compare with the container memory limit separately.
envoy_server_memory_allocatedmTLS 모니터링
# mTLS 사용률
sum(rate(istio_requests_total{
connection_security_policy="mutual_tls",
reporter="destination"
}[5m]))
/
sum(rate(istio_requests_total{reporter="destination"}[5m]))
* 100
# mTLS 미사용 트래픽 감지
sum(rate(istio_requests_total{
connection_security_policy="none",
reporter="destination"
}[5m])) by (source_workload, destination_workload)
# 인증된 메시 트래픽의 HTTP 401이며 TLS 핸드셰이크 실패가 아닙니다.
sum by (destination_service_name, destination_service_namespace) (
rate(istio_requests_total{reporter="destination",response_code="401",connection_security_policy="mutual_tls"}[5m])
)서비스 메시 health 대시보드
# Scrape health, not a complete control-plane health check.
up{job="istiod"}
# Istiod xDS build/send error rate, by type.
sum by (type) (rate(pilot_xds_pushes{type=~".*(builderr|senderr)"}[5m]))
# Configuration convergence time, seconds (not push count).
histogram_quantile(0.95,
sum by (le) (rate(pilot_proxy_convergence_time_bucket[5m]))
)
# Recently started Envoy process; uptime is elapsed seconds, not a timestamp.
envoy_server_uptime < 300실제 프록시 버전은 istioctl version, 동기화·NACK은 istioctl proxy-status로 확인합니다. 프로세스 나이는 설정 최신성을 나타내지 않으며 숫자형 Envoy version gauge를 버전 레이블 분포로 집계할 수 없습니다. mTLS 오류는 mTLS 가이드의 TLS 검증 카운터·인증서를 확인합니다.
메트릭 최적화
고카디널리티 문제 해결
1. 불필요한 레이블 제거
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: reduce-cardinality
namespace: istio-system
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: ALL_METRICS
tagOverrides:
# 고카디널리티 레이블 제거
request_id:
operation: REMOVE
user_agent:
operation: REMOVE2. 레이블 값 정규화
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: normalize-labels
namespace: prod
spec:
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
# HTTP 메서드를 정규화 (GET, POST, PUT, DELETE, OTHER)
request_method:
value: 'request.method in ["GET", "POST", "PUT", "DELETE"] ? request.method : "OTHER"'Envoy 통계 선택
proxyStatsMatcher는 생성할 Envoy 통계를 선택하며 요청을 샘플링하지 않습니다. 필요한 종류만 포함하고 기존 필수 조건을 유지하며 부트스트랩 변경 후 대상 프록시를 순차 교체합니다. 다음은 앞의 쿼리에 필요한 통계 활성화 예제입니다:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
defaultConfig:
proxyStatsMatcher:
inclusionRegexps:
- ".*upstream_rq_timeout.*"
- ".*upstream_cx_connect_timeout.*"
- ".*upstream_cx_connect_fail.*"
- ".*upstream_rq_pending_overflow.*"
- ".*circuit_breakers.*"
- ".*outlier_detection.*"
- ".*upstream_cx_(active|overflow).*"
- ".*upstream_rq_(active|retry|pending).*"Prometheus 성능 튜닝
Prometheus 기본 scrape 간격은 1분이며 15초·30초는 선택한 값입니다. 다음은 기존 scrape job에 병합할 설정 조각입니다. metric_relabel_configs는 각 scrape job 내부에 위치하고 레이블만이 아닌 샘플을 버립니다. Remote-write endpoint·인증/TLS·영속성은 선택한 백엔드에 맞춰 구성합니다.
global:
scrape_interval: 30s
evaluation_interval: 30s
remote_write:
- url: http://victoria-metrics:8428/api/v1/write
queue_config:
capacity: 10000
max_shards: 5
min_shards: 1
max_samples_per_send: 5000
scrape_configs:
- job_name: envoy-stats
metrics_path: /stats/prometheus
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_phase
action: keep
regex: Running
- source_labels:
- __meta_kubernetes_pod_container_name
- __meta_kubernetes_pod_container_port_name
action: keep
regex: istio-proxy;.*-envoy-prom
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
metric_relabel_configs:
- source_labels:
- __name__
regex: istio_tcp_.*
action: drop문제 해결
exec/curl 예제는 curl이 있는 프록시 이미지가 필요합니다. 없으면 kubectl port-forward pod/<pod-name> 15090:15090(agent는 15020) 후 다른 터미널에서 조회합니다. 여기의 Telemetry 예제는 Envoy 기준이며 ambient L7은 waypoint에 연결하고 ztunnel L4는 별도로 수집합니다.
메트릭이 수집되지 않을 때
1. Envoy 메트릭 엔드포인트 확인
# Envoy admin 포트 확인
kubectl exec -it <pod-name> -c istio-proxy -- curl localhost:15000/stats/prometheus | head -20
# 메트릭 필터 확인
istioctl proxy-config bootstrap <pod-name> -o json | jq '.bootstrap.statsConfig'2. Prometheus가 타겟을 발견했는지 확인
# Prometheus UI에서 Targets 페이지 확인
kubectl port-forward -n istio-system svc/prometheus 9090:9090
# 브라우저에서: http://localhost:9090/targets3. Telemetry API 설정 검증
# Telemetry 리소스 확인
kubectl get telemetry -A
# 특정 Telemetry 상세 확인
kubectl describe telemetry <name> -n <namespace>
# Envoy 설정에 반영되었는지 확인
istioctl proxy-config listeners <pod-name> -n <namespace> -o json메트릭 레이블이 누락되었을 때
# 1. Envoy가 올바른 레이블을 생성하는지 확인
kubectl exec -it <pod-name> -c istio-proxy -- curl localhost:15000/stats/prometheus | grep istio_requests_total | head -1
# 2. Prometheus relabeling 규칙 확인
kubectl get configmap prometheus-config -n istio-system -o yaml
# 3. ServiceMonitor/PodMonitor 확인
kubectl get servicemonitor,podmonitor -n istio-system메트릭 cardinality 폭발
다른 터미널에서 Prometheus를 port-forward한 뒤 활성 시계열과 TSDB 통계를 조회합니다. 메트릭 이름 수는 시계열 수가 아닙니다. TSDB status endpoint에는 레이블·값별 카디널리티도 포함됩니다.
curl -fsS http://localhost:9090/api/v1/status/tsdb | jq '.data'
curl -fsSG http://localhost:9090/api/v1/query \
--data-urlencode 'query=count(istio_requests_total)' | jq '.data.result'
curl -fsSG http://localhost:9090/api/v1/query \
--data-urlencode 'query=topk(10, count by (__name__) ({__name__=~"istio_.*"}))' | jq '.data.result'Circuit Breaker 메트릭이 보이지 않을 때
# 1. Envoy 클러스터 통계 확인
istioctl proxy-config cluster <pod-name> --fqdn <service-fqdn> -o json | \
jq '.[] | .circuitBreakers'
# 2. Envoy admin에서 직접 확인
kubectl exec -it <pod-name> -c istio-proxy -- \
curl "localhost:15000/clusters" | grep -A 10 "outbound|80||<service>"
# 3. DestinationRule이 올바르게 적용되었는지 확인
istioctl analyze -n <namespace>