본문으로 건너뛰기
05 요청 뒤에 남은 발자국 — 메트릭·로그·트레이스

05 · 요청 뒤에 남은 발자국 — 메트릭·로그·트레이스

같은 요청도 어느 프록시에서 보느냐에 따라 기록이 달라집니다. 먼저 호출 쪽과 대상 쪽을 나눠 봅니다.

정상적인 내부 호출을 양쪽 사이드카가 각각 관측합니다. reporter를 구분하지 않고 합산하면 같은 호출을 중복해서 셉니다.
도식 텍스트
  • 호출 앱
  • 호출 사이드카 — outbound
  • 대상 사이드카 — inbound
  • 대상 앱
  • source — 호출 쪽 메트릭
  • destination — 대상 쪽 메트릭
  • HTTP
  • mTLS
  • HTTP
  • 요청마다
  • 요청마다

요청 하나, 두 관측 지점

reporter="source"는 호출 쪽, reporter="destination"은 대상 쪽 프록시의 메트릭입니다. 둘을 합하면 정상적인 내부 호출도 중복 집계됩니다. 재시도나 연결 실패가 끼면 양쪽 수치가 달라질 수 있습니다.

대상 프록시가 받은 HTTP 요청의 5xx 비율은 이렇게 구합니다. 대상에 도착하기 전의 실패는 source 쪽에서 따로 확인합니다.

sum by (destination_service) (
  rate(istio_requests_total{reporter="destination", response_code=~"5.."}[5m])
)
/
sum by (destination_service) (
  rate(istio_requests_total{reporter="destination"}[5m])
)

호출 쪽 Envoy가 연결 실패로 503을 직접 만들었다면 요청이 대상 사이드카에 닿지 못해 기록은 source에만 남습니다. 정의에서 추론한 차이입니다.

HTTP를 해석하는 프록시에는 요청 수·상태 코드·지연이 보입니다. HTTP·gRPC로 분류된 요청에는 요청 수·지연·바이트 메트릭이 붙습니다. TCP로 처리하면 istio_tcp_* 네 개, 곧 연결 수와 바이트만 남습니다. 프로토콜을 정하지 않은 HTTP 서비스가 TCP로 분류되면 요청 메트릭은 나오지 않습니다. HTTP 메트릭이 없다면 03편의 프로토콜 분류부터 확인합니다.

기본 설정에서는 사이드카 메트릭과 앱 메트릭을 병합하며, 수집 주소는 :15020/stats/prometheus입니다. 프록시가 실제로 세는 값은 Envoy admin에서 직접 조회합니다.

kubectl exec deploy/web -c istio-proxy -- \
  pilot-agent request GET stats/prometheus | grep '^istio_requests_total' | head
근거와 출처
주장조건출처
HTTP 메트릭 4종, gRPC 메시지 메트릭 2종, TCP 메트릭 4종사이드카, 프로토콜 분류에 따름Istio Standard Metrics
reporter는 서버 쪽 프록시면 destination, 클라이언트 쪽 프록시나 게이트웨이면 source1.31.4 문서같은 문서
대상까지 못 간 요청은 source에만 남음구조상 도출, 호출 쪽 Envoy가 로컬 응답을 만든 경우위 정의와 Envoy response flag 정의에서 추론
메트릭 병합 기본 on, :15020/stats/prometheusmeshConfig.enablePrometheusMerge=false로 끔Istio Prometheus 통합

IP 뒤의 워크로드 이름

두 사이드카가 HTTP 요청·응답에 워크로드 정보를 실어 보내면 상대편 라벨을 채울 수 있습니다.
도식 텍스트
  • 호출 사이드카
  • 대상 사이드카
  • 대상 앱
  1. 1. 요청 + 호출 쪽 정보
  2. 2. 요청 전달
  3. 3. 응답
  4. source_* 라벨 채워 · destination 기록
  5. 4. 응답 + 대상 쪽 정보
  6. destination_* 라벨 채워 · source 기록

HTTP 메타데이터 교환과 istiod의 워크로드 정보가 source_workload 같은 라벨을 채웁니다. 워크로드 이름과 인증된 신원은 구분해야 합니다. source_principal의 신원 근거는 mTLS 피어 인증서입니다.

교환에 쓰는 헤더는 x-envoy-peer-metadata와 x-envoy-peer-metadata-id입니다. 필터 설정에는 istio_headers와 workload_discovery가 함께 들어가며, 조회 우선순위는 확인하지 못했습니다. TCP는 mTLS 핸드셰이크의 ALPN istio-peer-exchange로 교환합니다.

라벨이 비어 있거나 unknown인 이유도 여기서 찾습니다. 메시 밖 클라이언트가 호출하면 source_workload는 unknown입니다. source_principal은 mTLS 피어 인증서의 SPIFFE ID에서 오므로 평문 호출에서는 비어 있습니다.

mTLS 여부를 볼 때도 reporter="destination"을 고릅니다. connection_security_policy="mutual_tls"는 대상 쪽 기록에서 의미가 있고, source 쪽 값은 unknown입니다. 표준 메트릭 정의

근거와 출처
주장조건출처
표준 라벨 목록, source/destination_principal은 피어 인증을 쓸 때 채워짐1.31.4 문서Istio Standard Metrics
connection_security_policy는 destination에서 mutual_tls, source에서 unknown문서 정의같은 문서
사이드카 HTTP 필터 istio.metadata_exchange, discovery istio_headers·workload_discovery1.31.4 소스의 생성 설정istio/istio pilot/pkg/xds/filters/filters.go
헤더 이름 x-envoy-peer-metadata, x-envoy-peer-metadata-idistio/proxy e2e 테스트istio/proxy test/envoye2e/http_metadata_exchange
TCP는 ALPN istio-peer-exchange, PILOT_DISABLE_MX_ALPN으로 끔mTLS 연결istio/istio pilot/pkg/networking/util/util.go

503이 멈춘 자리

UF는 로그를 남긴 프록시의 업스트림 연결 실패를 뜻하므로, 어느 프록시의 기록인지에 따라 확인할 구간이 달라집니다.
도식 텍스트
  • 호출 사이드카
  • 대상 사이드카
  • 대상 앱
  1. 분기 — 대상 사이드카로 연결 실패
    1. 호출 쪽 로그: UF · 요청 전달 전 실패
    2. 연결 시도 · 실패
  2. 대상 사이드카에서 앱으로 연결 실패
    1. 대상 쪽 로그: UF · 앱 전달 전 실패
    2. HTTP 요청
    3. 앱 연결 · 실패
    4. 503 응답

UF는 그 로그를 남긴 프록시의 업스트림 연결 실패입니다. 호출 쪽의 업스트림은 대상 사이드카이고, 대상 쪽의 업스트림은 자기 앱입니다. 로그 누락만으로 도착 여부를 단정하기 전에, 양쪽의 로그 활성화·필터·수집 상태도 확인합니다.

flag먼저 확인할 곳
UF업스트림 연결·TLS 실패 사유
UH건강한 엔드포인트가 남아 있는지
UO연결 풀·요청 수 제한 초과
UT업스트림 응답 시간과 타임아웃
NR맞는 라우트나 filter chain이 없음

기본 TEXT 포맷에서 flag가 남은 줄만 추리는 명령입니다. 메트릭의 response_flags에도 같은 값이 들어갑니다.

kubectl logs deploy/web -c istio-proxy --since=10m | awk '$6 != "-"' | tail

Istio 1.31.4에서는 액세스 로그가 기본으로 꺼져 있고 데모 프로필만 켜져 있습니다. 다음은 기본 루트 네임스페이스인 istio-system에서 내장 envoy provider를 선택하는 예입니다.

apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
  name: access-log
  namespace: istio-system
spec:
  accessLogging:
    - providers:
        - name: envoy

같은 시간대의 response_flags와 업스트림 주소를 보고, 전파된 x-request-id로 양쪽 로그를 맞춥니다. 호출 쪽 로그에 UF가 있고 대상 쪽 로그에 같은 요청 ID가 없다면 요청은 대상 사이드카에 도착하지 못했습니다. 상태 코드만 같다고 같은 실패는 아닙니다. 액세스 로그 설정 · Envoy flag 정의

근거와 출처
주장조건출처
액세스 로그 기본 off, Telemetry API providers: [{name: envoy}] 권장데모 프로필만 /dev/stdoutIstio Envoy Access Logs
filter.expression은 CELTelemetry v1Telemetry API 레퍼런스
기본 포맷에 RESPONSE_FLAGS, RESPONSE_CODE_DETAILS, X-REQUEST-ID, UPSTREAM_HOST 포함EnvoyTextLogFormatistio/istio 1.31.4 pilot/pkg/model/telemetry_logging.go
response_flags 라벨 값은 Envoy 로그의 flag와 같음1.31.4 문서Istio Standard Metrics
awk 예시의 $6이 flag 칸기본 TEXT 포맷이고 공백이 없을 때기본 포맷에서 계산

앱이 이어 주는 트레이스

앱이 수신한 trace context를 다음 호출에 전달해야 여러 홉의 span이 같은 트레이스로 이어집니다.
도식 텍스트
  • 호출 서비스
  • 앱
  • 다음 서비스
  1. 요청 + trace context
  2. 분기 — trace context 전파
    1. 다음 요청 + context
    2. 같은 trace ID · 이어지는 span
  3. 전파 누락
    1. context 없는 요청
    2. 앞선 trace와 · 연결할 정보 없음

프록시는 앱이 새로 만든 요청이 어느 수신 요청에서 비롯됐는지 알 수 없습니다. 앱이나 계측 라이브러리가 traceparent·tracestate 또는 B3 context를 다음 호출에 전달해야 합니다. OpenTelemetry 자동 계측은 이 추출·주입과 앱 내부 span 생성을 맡을 수 있습니다. 이 과정이 빠지면 백엔드에는 홉마다 끊긴 짧은 트레이스만 쌓입니다.

OpenTelemetry provider는 meshConfig extensionProviders의 opentelemetry에 Collector 주소와 포트(gRPC 4317)를 적고, Telemetry의 tracing.providers와 randomSamplingPercentage로 고릅니다.

트레이스는 모든 요청을 담지 않습니다. 기본 샘플링 비율은 1%이며, 설정은 Telemetry API, 파드 어노테이션, MeshConfig 순으로 우선합니다. 경로가 모두 Envoy라면 첫 홉의 샘플링 결정을 x-request-id를 통해 뒤의 Envoy들도 이어받지만, 다른 프록시가 끼면 유지되지 않습니다.

요청 ID와 trace ID는 다릅니다. x-request-id는 홉별 로그를 맞추는 데 쓰고, trace ID는 트레이스 조회에 씁니다. 기본 로그에는 요청 ID가 있지만 trace ID는 없으므로, 필요하면 로그 포맷에 %TRACE_ID%를 추가합니다. 트레이싱 provider와 샘플링도 설정해야 하며, ID가 있어도 백엔드에 span이 저장되지 않았다면 조회할 트레이스는 없습니다. Istio 트레이싱과 헤더 전파

로그 포맷은 meshConfig의 envoyFileAccessLog.logFormat.text로 정의하고 Telemetry에서 provider 이름으로 선택합니다.

근거와 출처
주장조건출처
지원 백엔드 5종, 앱이 전파할 헤더 목록1.31.4 문서Distributed Tracing Overview
OTel provider gRPC 4317, HTTP 4318 /v1/traces1.31.4 문서OpenTelemetry 작업 문서
기본 샘플링 1%, 우선순위 Telemetry API > 파드 어노테이션 > MeshConfig퍼센트 샘플러Sampling
기본 포맷에 X-REQUEST-ID는 있고 TRACE_ID는 없음EnvoyTextLogFormatistio/istio 1.31.4 telemetry_logging.go
비샘플 요청의 trace ID 출력 여부확인하지 못함—

남길 기록의 범위

메트릭으로 어느 서비스·시간대가 나쁜지, 로그로 어느 홉에서 실패했는지, 트레이스로 호출이 어떻게 이어졌는지를 찾습니다. 메트릭의 합계에서 특정 요청 하나를 바로 찾을 수는 없습니다.

사용자 ID·원문 URL처럼 값이 계속 늘어나는 정보는 메트릭 라벨 대신 로그·span에 둡니다. 라벨은 Telemetry의 tagOverrides로 줄일 수 있습니다. source 메트릭을 끄면 대상 도착 전 실패도 놓치므로, 중복 집계 방지를 위해 수집 자체를 끌 필요는 없습니다. Telemetry API

설정을 놓는 위치도 결과를 바꿉니다. Telemetry는 루트 네임스페이스, 네임스페이스, selector 워크로드 순으로 적용되며 자식의 필드는 부모의 필드를 병합 없이 덮어씁니다.

Ambient의 ztunnel은 연결 단위, waypoint는 HTTP 요청 단위로 관측합니다. ztunnel은 L4만 처리하므로 메트릭은 istio_tcp_* 네 개이고, 로그는 연결이 끝날 때 쓰는 connection complete 한 줄이며 상태 코드와 response flag가 없습니다. 요청 단위 기록이 필요한 서비스에는 waypoint를 붙입니다. waypoint는 Envoy이므로 표준 메트릭과 액세스 로그, span을 사이드카처럼 남깁니다.

요청 경로의 L7 프록시가 waypoint 하나이므로 위의 두 사이드카 그림과 reporter 조건을 그대로 옮기지 말고 실제 경로에서 확인합니다. reporter 정의에 waypoint 값이 없고 실제 값도 확인하지 못했습니다. Ambient의 L7 기능 · ambient를 왜 쓰나

근거와 출처
주장조건출처
ztunnel만 쓰면 L4 TCP 메트릭 4종, waypoint가 있으면 Istio·Envoy 메트릭 전체1.31.4 문서Troubleshoot ztunnel, L7 features
ztunnel 로그 필드connection complete 레코드Troubleshoot ztunnel
waypoint 경로의 reporter 값문서에 waypoint 값이 없음, 실제 값은 확인하지 못함Istio Standard Metrics

← 04 L7 프록시가 여는 기능 · 시리즈 처음으로

마지막 수정 일자