Istio Hands-on Study [1기]

[4주차] 관찰 가능성(네트워크 동작 시각화하기) : 분산 추적

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

🌐 Distributed Tracing 이란 무엇인가?

  • 마이크로서비스 아키텍처가 점점 더 보편화되면서, 여러 분산된 컴포넌트들이 서로 협력하여 비즈니스 목표를 달성하는 시스템이 많아지고 있습니다. 이런 시스템에서는 요청이 여러 서비스를 거치며 처리되는데, 이 과정에서 문제가 발생하면 빠르게 원인을 파악하고 해결해야 합니다. Distributed tracing은 이러한 분산 시스템에서 요청의 흐름을 추적하고 문제를 진단하는 데 핵심적인 역할을 합니다.

  • 요청이 여러 서비스를 거쳐 처리되는 과정을 시각화한 다이어그램입니다. 각 서비스 간 이동(hop)과 소요 시간을 추적할 수 있어야 합니다.
Distributed tracing은 마이크로서비스 환경에서
요청의 경로와 성능을 추적하여 문제를 빠르게 진단할 수 있도록 도와줍니다.

🛠️ 모놀리스 vs 마이크로서비스: 디버깅의 차이점

  • 모놀리스(monolith) 애플리케이션에서는 문제가 발생했을 때 디버거, 런타임 프로파일러, 메모리 분석 도구 같은 익숙한 도구를 사용해 코드의 문제 지점을 쉽게 찾을 수 있습니다. 하지만 마이크로서비스로 구성된 분산 시스템에서는 각 서비스가 독립적으로 동작하기 때문에 기존 도구만으로는 한계가 있습니다. 요청이 여러 서비스를 거치며 발생하는 지연(latency)이나 오류(fault)를 추적하려면 새로운 접근 방식이 필요합니다.
  • Distributed tracing은 이러한 분산 시스템의 요청 흐름을 시각화하고, 어떤 서비스에서 문제가 발생했는지, 각 단계에서 얼마나 시간이 걸렸는지 등을 명확히 보여줍니다. 이를 통해 개발자는 전체 시스템의 동작을 이해하고 문제를 빠르게 해결할 수 있습니다.
모놀리스와 달리 마이크로서비스에서는 분산된 요청 흐름을 추적하기 위해
distributed tracing 같은 새로운 도구가 필수적입니다.

🔍 Distributed Tracing의 기본 개념

  • Distributed tracing은 Google의 Dapper 논문에서 처음 소개된 개념입니다. 이 기술은 요청이 시스템을 통과하는 동안 각 서비스 호출에 고유한 correlation ID와 전체 요청을 나타내는 trace ID를 추가하여 추적합니다.
# Correlation ID와 Trace ID의 역할
- Correlation ID: 서비스 간 호출을 식별하는 고유 ID
- Trace ID: 하나의 요청이 시스템을 통과하는 전체 경로를 나타내는 ID
  • 이러한 ID를 통해 요청이 어떤 서비스를 거쳤는지, 각 서비스에서 얼마나 시간이 소요되었는지, 어디서 문제가 발생했는지 등을 한눈에 파악할 수 있습니다.
  • Istio는 이러한 메타데이터를 자동으로 요청에 추가하고, 외부에서 들어오는 알 수 없는 메타데이터는 제거하여 보안성을 높입니다.
Distributed tracing은 correlation ID와 trace ID를 활용해
요청의 전체 경로를 추적하고 문제를 진단합니다.

📊 OpenTelemetry와 Istio의 역할

  • Distributed tracing을 구현하려면 개발자가 직접 애플리케이션 코드를 수정하여 요청을 추적할 수 있도록 instrumentation 작업을 해야 합니다. 하지만 이는 시간과 노력이 많이 드는 작업입니다. 여기서 OpenTelemetry와 Istio가 큰 도움을 줍니다.

OpenTelemetry란?

  • OpenTelemetry는 distributed tracing을 위한 오픈소스 프레임워크로, OpenTracing이라는 표준 스펙을 포함합니다. 이를 통해 요청 흐름을 추적하기 위한 API와 개념을 제공합니다. 개발자는 OpenTelemetry를 사용해 애플리케이션에서 요청을 처리하거나 다른 시스템으로 요청을 보낼 때 이를 기록할 수 있습니다.

Istio의 기여

  • Istio는 서비스 메시(service mesh)로서 distributed tracing의 많은 작업을 자동화합니다. 개발자가 직접 코드를 수정하지 않아도, Istio의 데이터 플레인(data plane)이 요청에 필요한 메타데이터를 추가하고 추적 정보를 수집합니다. 이를 통해 전체 요청 흐름을 시각화하고 문제가 발생한 지점을 빠르게 파악할 수 있습니다.
OpenTelemetry는 distributed tracing을 위한 표준을 제공하며,
Istio는 이를 자동화하여 개발자의 부담을 줄여줍니다.

🚀 Istio로 Distributed Tracing 구현하기

  • Istio를 사용하면 distributed tracing을 구현하는 데 필요한 복잡한 작업을 간소화할 수 있습니다. Istio는 다음과 같은 기능을 제공합니다:
    • 자동 메타데이터 추가: 요청이 서비스를 통과할 때 correlation ID와 trace ID를 자동으로 삽입합니다.
    • 외부 요청 보안 처리: 외부에서 들어오는 알 수 없는 메타데이터를 제거하여 보안을 강화합니다.
    • 추적 데이터 수집: 요청 흐름을 시각화할 수 있는 데이터를 수집하여 개발자가 문제 지점을 쉽게 파악하도록 돕습니다.
Istio는 distributed tracing의 복잡한 작업을 자동화하여
요청 추적과 문제 진단을 간편하게 만듭니다.

📌 핵심 요약

  • Distributed tracing은 마이크로서비스 환경에서 요청의 경로와 성능을 추적하여 문제를 빠르게 진단하는 기술입니다.
  • 모놀리스와 달리 분산 시스템에서는 기존 디버깅 도구의 한계를 극복하기 위해 distributed tracing이 필요합니다.
  • Google의 Dapper 논문에서 시작된 이 기술은 correlation IDtrace ID를 사용해 요청 흐름을 추적합니다.
  • OpenTelemetry는 distributed tracing을 위한 표준 프레임워크를 제공하며, Istio는 이를 자동화하여 개발자의 부담을 줄입니다.
  • Istio는 메타데이터 추가, 외부 요청 보안 처리, 추적 데이터 수집 등을 통해 효율적인 distributed tracing을 지원합니다.

🌐 Distributed Tracing의 작동 원리

  • 마이크로서비스 아키텍처에서 요청이 여러 서비스를 거치며 처리될 때, 문제가 발생하면 그 원인을 빠르게 파악하는 것이 중요합니다. Distributed tracing은 요청의 전체 경로를 추적하여 어떤 서비스에서 문제가 발생했는지, 각 단계에서 얼마나 시간이 걸렸는지를 시각화하는 기술입니다.

🔍 OpenTracing과 Span의 기본 개념

  • Distributed tracing의 핵심은 OpenTracing이라는 표준 프레임워크를 기반으로 동작합니다.
  • OpenTracing에서는 애플리케이션이 요청을 처리할 때 Span이라는 데이터를 생성하고, 이를 OpenTracing engine에 전달합니다.
  • Span은 서비스나 컴포넌트 내에서 수행된 작업 단위를 나타내는 데이터로, 다음과 같은 정보를 포함합니다:
    • 작업의 시작 시간(start time)
    • 작업의 종료 시간(end time)
    • 작업 이름(operation name)
    • 태그(tags)와 로그(logs)
  • 애플리케이션은 Span을 생성한 후, 요청이 다른 서비스로 전달될 때 trace context를 함께 전달합니다. 이 과정을 반복하며, 각 서비스는 자신의 작업에 대한 Span을 생성하고 이를 OpenTracing engine에 보냅니다. 이렇게 수집된 Span들은 Trace라는 전체 요청 경로를 나타내는 데이터로 조합됩니다. Trace는 서비스 간의 인과 관계, 호출 방향, 소요 시간, 디버깅 정보를 보여줍니다.
# Span의 구조 예시
Span {
  id: "span-123",
  trace_id: "trace-456",
  operation_name: "GET /api/data",
  start_time: "2025-04-21T10:00:00",
  end_time: "2025-04-21T10:00:01",
  tags: { "http.status": "200" },
  logs: [ "Request processed" ]
}
  • 각 네트워크 호출(hop)마다 Span을 수집하고, 이를 전체 Trace로 조합하여 호출 그래프의 문제를 디버깅할 수 있습니다.

OpenTracing은 Span을 통해 작업 단위를 기록하고,
이를 Trace로 조합하여 요청의 전체 흐름을 추적합니다.

🛠️ Span과 Trace ID의 역할

  • 각 Span은 고유한 Span ID와 전체 요청을 식별하는 Trace ID를 가집니다. 이 ID들은 서비스 간 호출을 상호 연관시키는 데 사용됩니다.
    예를 들어, 서비스 A가 서비스 B를 호출하면, 서비스 A의 Span과 서비스 B의 Span은 동일한 Trace ID를 공유하여 두 작업이 같은 요청의 일부임을 나타냅니다.
  • 이러한 ID들은 서비스 간에 전달(propagate)되어야 하며, 이를 통해 distributed tracing engine은 요청이 시스템을 통과하는 전체 경로를 재구성할 수 있습니다. OpenTracing을 구현하는 주요 시스템으로는 다음과 같은 것들이 있습니다:
    • Jaeger
    • Zipkin
    • Lightstep
    • Instana
  • 이 시스템들은 Span을 수집하고 Trace를 시각화하여 개발자가 문제를 쉽게 진단할 수 있도록 돕습니다.
Span ID와 Trace ID는 서비스 간 호출을 연결하여
전체 요청 경로를 추적하는 데 필수적입니다.

🚀 Istio의 Distributed Tracing 지원

  • Istio는 distributed tracing을 구현하는 데 필요한 복잡한 작업을 간소화합니다. Istio의 서비스 프록시(service proxy) 는 요청이 시스템을 통과할 때 자동으로 Span을 생성하고, 이를 distributed tracing engine으로 전송합니다. 개발자가 언어별 라이브러리나 애플리케이션별 설정을 직접 관리할 필요가 없습니다.
  • Istio는 다음과 같은 방식으로 distributed tracing을 지원합니다:
    • 새로운 Trace 시작: 요청에 기존 Trace가 없으면 Istio가 새로운 Trace를 시작합니다.
    • Span 데이터 캡처: 요청의 시작 시간과 종료 시간을 Span의 일부로 기록합니다.
    • Tracing 헤더 추가: Istio는 요청에 Zipkin tracing headers를 추가하여 Span과 Trace를 상호 연관시킵니다.
  • Istio가 사용하는 주요 Zipkin tracing headers는 다음과 같습니다:
# Istio에서 사용하는 Zipkin tracing headers
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
  • 만약 요청에 이미 tracing headers가 포함되어 있다면, Istio는 이를 인-progress Trace로 인식하고 새로운 Trace를 생성하지 않습니다.
Istio는 Span 생성과 tracing headers 추가를 자동화하여
distributed tracing을 간편하게 만듭니다.

📡 Tracing Headers의 전파 필요성

  • Distributed tracing이 요청의 전체 경로를 정확히 추적하려면, 애플리케이션이 tracing headers를 후속 호출(outgoing calls)로 전달(propagate)해야 합니다.
  • Istio는 들어오는 요청(incoming requests)과 나가는 요청(outgoing calls)을 직접 연결할 수 없기 때문에, 애플리케이션이 이 헤더를 전달하는 역할을 맡아야 합니다.

  • 애플리케이션이 tracing headers를 전달하지 않으면 요청의 전체 경로를 추적할 수 없습니다.

  • 다행히도 많은 RPC 프레임워크(예: gRPC, Spring 등)는 OpenTracing을 기본적으로 지원하거나 통합하여 tracing headers를 자동으로 전달합니다. 그렇지 않은 경우, 개발자는 애플리케이션 코드에서 헤더를 수동으로 전달해야 합니다.
# tracing headers 전파 예시 (의사 코드)
http_client.request(
  url: "http://service-b/api",
  headers: {
    "x-b3-traceid": incoming_request.headers["x-b3-traceid"],
    "x-b3-spanid": generate_new_span_id(),
    ...
  }
)
애플리케이션은 tracing headers를 후속 호출로 전달해야
전체 요청 경로를 정확히 추적할 수 있습니다.

📌 핵심 요약

  • OpenTracing은 Span을 통해 서비스 내 작업을 기록하고, Trace로 조합하여 요청의 전체 경로를 추적합니다.
  • Span IDTrace ID는 서비스 간 호출을 연결하여 distributed tracing의 핵심 역할을 합니다.
  • Istio는 Span 생성, tracing headers 추가, Trace 데이터 전송을 자동화하여 distributed tracing을 간소화합니다.
  • Istio는 Zipkin tracing headers를 사용하여 Span과 Trace를 상호 연관시킵니다.
  • 애플리케이션은 tracing headers를 후속 호출로 전달(propagate)해야 전체 요청 경로를 정확히 추적할 수 있습니다.
  • Jaeger, Zipkin, Lightstep, Instana 같은 시스템은 Span을 수집하고 Trace를 시각화하여 디버깅을 지원합니다.

🌐 Distributed Tracing 시스템 설치하기


🛠️ Jaeger All-in-One 배포의 특징

  • Jaeger는 distributed tracing을 위한 오픈소스 도구로, 요청의 Span과 Trace를 수집하고 시각화합니다.
    프로덕션 환경에서는 데이터베이스와 같은 추가 컴포넌트가 필요하지만, 이번 예제에서는 간단한 테스트를 위해 Jaeger all-in-one 배포를 사용합니다. 이 배포는 다음과 같은 장점이 있습니다:
    • 별도의 데이터베이스 설정 없이 바로 사용할 수 있습니다.
    • Istio가 기본적으로 기대하는 Zipkin 서비스를 포함하여 호환성을 제공합니다.
  • Jaeger는 Zipkin 포맷과 호환되며, Istio와 쉽게 통합됩니다.
    프로덕션 환경에서의 Jaeger 배포는 더 복잡하므로, 자세한 내용은 Jaeger 공식 문서를 참고하세요(http://mng.bz/GGdN).
Jaeger all-in-one 배포는 테스트 환경에서 간단히 사용할 수 있으며,
Zipkin 포맷을 지원해 Istio와 통합이 용이합니다.

🚀 Jaeger 설치하기

  • Jaeger를 설치하려면 Istio 샘플 디렉토리에 포함된 jaeger.yaml 파일을 사용합니다.
    아래 명령어를 실행하여 Kubernetes 클러스터에 Jaeger를 배포합니다:
(⎈|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:/# ls istio-$ISTIOV/samples/addons
README.md  extras  grafana.yaml  jaeger.yaml  kiali.yaml  prometheus.yaml

root@myk8s-control-plane:/# cat istio-$ISTIOV/samples/addons/jaeger.yaml
### Jaeger 배포(Deployment) ###
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jaeger # 배포 이름: jaeger
  namespace: istio-system # 배포가 속할 네임스페이스: istio-system
  labels:
    app: jaeger # 이 배포를 식별하는 레이블: app=jaeger
spec:
  selector:
    matchLabels:
      app: jaeger # 이 배포로 관리되는 파드를 선택하는 레이블 셀렉터: app=jaeger
  template: # 파드 템플릿 정의
    metadata:
      labels:
        app: jaeger # 이 템플릿으로 생성될 파드를 식별하는 레이블: app=jaeger
        sidecar.istio.io/inject: "false" # Istio 사이드카 자동 주입 비활성화
      annotations:
        prometheus.io/scrape: "true" # Prometheus 스크래핑 활성화
        prometheus.io/port: "14269" # Prometheus 스크래핑 포트: 14269 (Jaeger Agent 기본 포트)
    spec:
      containers:
        - name: jaeger # 컨테이너 이름: jaeger
          image: "docker.io/jaegertracing/all-in-one:1.35" # 사용할 Docker 이미지: jaegertracing/all-in-one:1.35 (Jaeger All-in-One 버전)
          env: # 컨테이너 환경 변수 설정
            - name: BADGER_EPHEMERAL
              value: "false" # BadgerDB를 임시 모드로 사용하지 않음 (데이터 영구 저장)
            - name: SPAN_STORAGE_TYPE
              value: "badger" # 스팬 저장 타입: BadgerDB (내장형 데이터베이스)
            - name: BADGER_DIRECTORY_VALUE
              value: "/badger/data" # BadgerDB 데이터 저장 경로
            - name: BADGER_DIRECTORY_KEY
              value: "/badger/key" # BadgerDB 키 저장 경로
            - name: COLLECTOR_ZIPKIN_HOST_PORT
              value: ":9411" # Zipkin 스팬 수집을 위한 호스트 및 포트 설정 (모든 인터페이스의 9411 포트)
            - name: MEMORY_MAX_TRACES
              value: "50000" # 인메모리 저장 시 최대 트레이스 수
            - name: QUERY_BASE_PATH
              value: /jaeger # Jaeger UI 기본 경로
          livenessProbe: # 컨테이너 생존성 검사 설정
            httpGet:
              path: / # HTTP GET 요청 경로: /
              port: 14269 # HTTP GET 요청 포트: 14269 (Jaeger Agent 기본 포트)
          readinessProbe: # 컨테이너 준비성 검사 설정
            httpGet:
              path: / # HTTP GET 요청 경로: /
              port: 14269 # HTTP GET 요청 포트: 14269 (Jaeger Agent 기본 포트)
          volumeMounts: # 볼륨 마운트 설정
            - name: data # 마운트할 볼륨 이름: data
              mountPath: /badger # 컨테이너 내 마운트 경로: /badger
          resources: # 컨테이너 자원 요청 설정
            requests:
              cpu: 10m # CPU 요청: 10 millicores
      volumes: # 파드 내 볼륨 정의
        - name: data # 볼륨 이름: data
          emptyDir: {} # emptyDir 타입 볼륨 (파드 생명주기와 동일)
---
### Jaeger Query Service ###
apiVersion: v1
kind: Service
metadata:
  name: tracing # 서비스 이름: tracing
  namespace: istio-system # 서비스가 속할 네임스페이스: istio-system
  labels:
    app: jaeger # 이 서비스를 식별하는 레이블: app=jaeger
spec:
  type: ClusterIP # 클러스터 내부 IP를 통해만 접근 가능한 서비스 타입
  ports:
    - name: http-query # 포트 이름: http-query
      port: 80 # 서비스 포트: 80
      protocol: TCP # 프로토콜: TCP
      targetPort: 16686 # 파드 내부 컨테이너 포트: 16686 (Jaeger Query UI 기본 포트)
    # Note: Change port name if you add '--query.grpc.tls.enabled=true'
    - name: grpc-query # 포트 이름: grpc-query
      port: 16685 # 서비스 포트: 16685
      protocol: TCP # 프로토콜: TCP
      targetPort: 16685 # 파드 내부 컨테이너 포트: 16685 (Jaeger Query GRPC 기본 포트)
  selector:
    app: jaeger # 이 서비스가 연결할 파드를 선택하는 레이블 셀렉터: app=jaeger
---
### Zipkin 호환 서비스 ###
# Jaeger implements the Zipkin API. To support swapping out the tracing backend, we use a Service named Zipkin.
apiVersion: v1
kind: Service
metadata:
  labels:
    name: zipkin # 서비스 레이블: name=zipkin
  name: zipkin # 서비스 이름: zipkin
  namespace: istio-system # 서비스가 속할 네임스페이스: istio-system
spec:
  ports:
    - port: 9411 # 서비스 포트: 9411 (Zipkin 기본 포트)
      targetPort: 9411 # 파드 내부 컨테이너 포트: 9411 (Jaeger Collector Zipkin 수신 포트)
      name: http-query # 포트 이름: http-query
  selector:
    app: jaeger # 이 서비스가 연결할 파드를 선택하는 레이블 셀렉터: app=jaeger
---
### Jaeger Collector Service ###
apiVersion: v1
kind: Service
metadata:
  name: jaeger-collector # 서비스 이름: jaeger-collector
  namespace: istio-system # 서비스가 속할 네임스페이스: istio-system
  labels:
    app: jaeger # 이 서비스를 식별하는 레이블: app=jaeger
spec:
  type: ClusterIP # 클러스터 내부 IP를 통해만 접근 가능한 서비스 타입
  ports:
    - name: jaeger-collector-http # 포트 이름: jaeger-collector-http
      port: 14268 # 서비스 포트: 14268
      targetPort: 14268 # 파드 내부 컨테이너 포트: 14268 (Jaeger Collector HTTP 수신 포트)
      protocol: TCP # 프로토콜: TCP
    - name: jaeger-collector-grpc # 포트 이름: jaeger-collector-grpc
      port: 14250 # 서비스 포트: 14250
      targetPort: 14250 # 파드 내부 컨테이너 포트: 14250 (Jaeger Collector GRPC 수신 포트)
      protocol: TCP # 프로토콜: TCP
    - port: 9411 # 서비스 포트: 9411 (Zipkin 기본 포트)
      targetPort: 9411 # 파드 내부 컨테이너 포트: 9411 (Jaeger Collector Zipkin 수신 포트)
      name: http-zipkin # 포트 이름: http-zipkin
  selector:
    app: jaeger # 이 서비스가 연결할 파드를 선택하는 레이블 셀렉터: app=jaeger
  • 이 명령어는 다음과 같은 리소스를 생성합니다:
root@myk8s-control-plane:/# kubectl apply -f istio-$ISTIOV/samples/addons/jaeger.yaml
deployment.apps/jaeger created
service/tracing created
service/zipkin created
service/jaeger-collector created
  • 배포가 완료되면 istio-system 네임스페이스에 Jaeger 관련 Pod이 실행 중인지 확인합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get pod -n istio-system
NAME                                    READY   STATUS    RESTARTS   AGE
istio-egressgateway-85df6b84b7-h6sbn    1/1     Running   0          21h
istio-ingressgateway-6bb8fb6549-wft8c   1/1     Running   0          21h
istiod-8d74787f-ctmmf                   1/1     Running   0          21h
jaeger-5556cd8fcf-fr7b2                 1/1     Running   0          2m53s
  • 클러스터 바깥에서도 노드IP:30004로 접속할 수 있게 설정

 

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'
service/tracing patched

 

jaeger.yaml 파일을 사용해 Jaeger를 설치하면
Kubernetes에 필요한 Pod과 서비스가 자동으로 생성됩니다.

🔍 설치된 서비스 확인하기

  • Jaeger 배포 후, istio-system 네임스페이스에 생성된 서비스를 확인합니다:
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get svc -n istio-system
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                      AGE
istio-egressgateway    ClusterIP      10.200.1.87    <none>        80/TCP,443/TCP                                                               21h
istio-ingressgateway   LoadBalancer   10.200.1.140   <pending>     15021:30966/TCP,80:30000/TCP,443:30005/TCP,31400:30013/TCP,15443:31613/TCP   24h
istiod                 ClusterIP      10.200.1.117   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        24h
jaeger-collector       ClusterIP      10.200.1.211   <none>        14268/TCP,14250/TCP,9411/TCP                                                 3m9s
tracing                NodePort       10.200.1.18    <none>        80:30004/TCP,16685:31460/TCP                                                 3m9s
zipkin                 ClusterIP      10.200.1.28    <none>        9411/TCP

 

  • 여기서 zipkin 서비스가 포함된 것을 확인할 수 있습니다. 이 서비스는 Istio가 Jaeger와 통신할 때 사용하는 기본 엔드포인트입니다. 출력 결과가 위와 비슷하다면 Jaeger 설치가 정상적으로 완료된 것입니다.
설치 후 zipkin 서비스를 확인하여 Istio와 Jaeger의 통합 준비가 완료되었는지 점검합니다.

📡 다음 단계: Istio 데이터 플레인 설정

  • Jaeger 설치가 완료되었으니, Istio의 데이터 플레인(data plane) 을 설정하여 생성된 Jaeger 서비스로 Trace 데이터를 전송하도록 해야 합니다. 이 과정은 Istio가 요청의 Span을 수집하고 Jaeger로 전달하도록 구성하는 단계입니다. 
Jaeger 설치 후, Istio 데이터 플레인을 설정하여 Trace 데이터를 Jaeger로 전송할 준비를 합니다.

📌 핵심 요약

  • Jaeger all-in-one 배포는 테스트 환경에서 간단히 사용할 수 있는 distributed tracing 솔루션으로, Zipkin 포맷을 지원해 Istio와 통합이 용이합니다.
  • kubectl apply -f istio-1.13.0/samples/addons/jaeger.yaml 명령어로 Jaeger를 Kubernetes 클러스터에 설치합니다.
  • 설치 후 istio-system 네임스페이스에서 Jaeger Pod과 zipkin 서비스가 정상적으로 생성되었는지 확인합니다.
  • 프로덕션 환경에서는 추가적인 데이터베이스 설정이 필요하며, Jaeger 공식 문서를 참고해야 합니다.
  • Jaeger 설치 완료 후, Istio 데이터 플레인을 설정하여 Trace 데이터를 Jaeger로 전송하도록 구성해야 합니다.

🚀 Istio로
분산 추적(Distributed Tracing) 설정


🛠️ 설치 시 분산 추적 설정하기

  • Istio는 Zipkin, Datadog, Jaeger(Zipkin 호환), Stackdriver 등 다양한 분산 추적 백엔드를 지원합니다.
    설치 시 IstioOperator 리소스를 사용해 추적 백엔드를 설정할 수 있습니다.
    아래는 여러 백엔드를 설정하는 예제입니다.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
spec:
  meshConfig:
    defaultConfig:
      tracing:
        lightstep: {} #Lightstep 트레이싱 백엔드 설정을 정의하는 부분
        zipkin: {} #Zipkin 트레이싱 백엔드 설정을 정의
        datadog: {} #Datadog APM 트레이싱 백엔드 설정을 정의
        stackdriver: {} #Google Cloud의 Stackdriver (현재는 Cloud Trace) 트레이싱 백엔드 설정을 정의
  • Jaeger를 사용하려면 Zipkin 호환 설정을 다음과 같이 구성합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/install-istio-tracing-zipkin.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
spec:
  meshConfig: #Istio Mesh 전체에 적용될 기본 설정을 정의
    defaultConfig: #워크로드에 주입되는 Envoy 사이드카 프록시의 기본 설정을 정의
      tracing: #트레이싱 관련 설정을 정의
        sampling: 100 #트레이스 샘플링 비율을 100으로 설정합니다. 이는 모든 요청에 대한 트레이스 정보를 수집하겠다는 의미
        zipkin: #트레이스 정보를 Zipkin 백엔드로 전송하도록 설정
          address: zipkin.istio-system:9411 #Zipkin 서버의 주소를 zipkin.istio-system:9411로 지정
  • 이 설정을 적용하려면 다음 명령어를 실행합니다.
(⎈|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 > 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
EOF

root@myk8s-control-plane:/# istioctl install -y -f install-istio-tracing-zipkin.yaml
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
- Pruning removed resources                                                                                       Removed Deployment:istio-system:istio-egressgateway.
  Removed Service:istio-system:istio-egressgateway.
  Removed ServiceAccount:istio-system:istio-egressgateway-service-account.
  Removed RoleBinding:istio-system:istio-egressgateway-sds.
  Removed Role:istio-system:istio-egressgateway-sds.
  Removed PodDisruptionBudget:istio-system:istio-egressgateway.
✔ 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

root@myk8s-control-plane:/# exit
exit
  • 이 명령은 Istio를 설치하면서 지정된 추적 백엔드(Jaeger)를 글로벌 메쉬에 설정합니다.

설치 시 IstioOperator를 사용해 Zipkin, Jaeger 등의 추적 백엔드를 글로벌 메쉬에 쉽게 설정할 수 있습니다.


🔧 MeshConfig로 추적 설정하기

  • Istio 설치 후 추적 백엔드를 설정하지 않았거나 기존 설정을 변경하고 싶다면, MeshConfig 객체를 수정할 수 있습니다. MeshConfig는 istio-system 네임스페이스의 istio ConfigMap에 저장되어 있습니다.
    다음 명령어로 현재 설정을 확인할 수 있습니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl describe cm -n istio-system istio
...
defaultConfig:
  discoveryAddress: istiod.istio-system.svc:15012
  proxyMetadata: {}
  tracing:
    sampling: 100
    zipkin:
      address: zipkin.istio-system:9411
enablePrometheusMerge: true
rootNamespace: istio-system
trustDomain: cluster.local
...
  • defaultConfig.tracing 섹션에서 추적 설정을 수정해 원하는 백엔드 주소나 옵션을 업데이트할 수 있습니다. 예를 들어, Jaeger의 주소를 변경하거나 다른 백엔드로 전환할 수 있습니다.

MeshConfig를 수정하면 설치 후에도 글로벌 추적 설정을 유연하게 변경할 수 있습니다.


⚙️ 워크로드별 추적 설정하기

  • 글로벌 설정 외에도 특정 워크로드에만 추적을 설정하고 싶을 때가 있습니다.
    이를 위해 Deployment 리소스의 어노테이션을 사용해 개별 워크로드에 추적 설정을 적용할 수 있습니다.
apiVersion: apps/v1
kind: Deployment
...
spec:
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |
          tracing:
            zipkin:
              address: zipkin.istio-system:9411
  • 이 설정은 해당 Deployment에 속한 워크로드에만 Zipkin 추적을 적용합니다. 이를 통해 특정 서비스에 맞춘 세밀한 추적 설정이 가능합니다.

워크로드별 추적 설정은 Deployment의 어노테이션을 통해 세밀하게 제어할 수 있습니다.


🔍 기본 추적 헤더 살펴보기

  • 추적 백엔드 설정이 완료되었다면, Istio가 올바르게 추적 헤더를 생성하는지 확인해보겠습니다.
  • Istio는 OpenTracing 표준 헤더(Zipkin의 x-b3-* 헤더)를 자동으로 주입합니다.
    이를 테스트하기 위해 Istio의 ingress gateway를 통해 외부 서비스(httpbin)에 요청을 보내고, 반환된 헤더를 확인합니다.
  • 먼저, httpbin으로 라우팅하는 VirtualService를 배포합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/tracing/thin-httpbin-virtualservice.yaml
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector: #이 Gateway가 어떤 Istio Ingress Gateway 인스턴스에 적용될지를 결정하는 레이블 셀렉터
    istio: ingressgateway # use istio default controller
  servers: #이 Gateway가 수신할 트래픽 설정을 정의
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts: #이 Gateway가 처리할 호스트 이름을 정의
    - "webapp.istioinaction.io" #webapp.istioinaction.io 호스트로 들어오는 트래픽을 이 Gateway가 처리
    - "httpbin.istioinaction.io" #httpbin.istioinaction.io 호스트로 들어오는 트래픽도 이 Gateway가 처리
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: thin-httbin-virtualservice
spec:
  hosts:
  - "httpbin.istioinaction.io"
  gateways: #이 VirtualService이 적용될 Gateway 이름을 정의
  - coolstore-gateway
  http: #HTTP 트래픽 라우팅 규칙을 정의
  - route:
    - destination:
        host: httpbin.org
---
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-httpbin-org
spec:
  hosts:
  - httpbin.org #외부 서비스의 호스트 이름은 httpbin.org
  ports:
  - number: 80 #외부 서비스의 포트 번호는 80
    name: http
    protocol: HTTP
  location: MESH_EXTERNAL #이 서비스가 Istio 메시 외부(external)에 위치함
  resolution: DNS #Istio가 이 서비스의 IP 주소를 DNS를 통해 확인하도록 지시


(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f ch8/tracing/thin-httpbin-virtualservice.yaml
gateway.networking.istio.io/coolstore-gateway configured
virtualservice.networking.istio.io/thin-httbin-virtualservice created
serviceentry.networking.istio.io/external-httpbin-org created
  • 도메인 질의를 위한 임시 설정
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ echo "127.0.0.1       httpbin.istioinaction.io" | sudo tee -a /etc/hosts
cat /etc/hosts | tail -n 5
[sudo] password for ssoon:
127.0.0.1       httpbin.istioinaction.io

 

다음으로, ingress gateway를 호출해 httpbin의 /headers 엔드포인트를 요청합니다.

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s http://httpbin.istioinaction.io:30000/headers | jq
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.istioinaction.io",
    "User-Agent": "curl/8.5.0",
    "X-Amzn-Trace-Id": "Root=1-68105c7a-696ee0b97f4d4aa0630dc05a",
    "X-B3-Sampled": "1",
    "X-B3-Spanid": "ae0aef19cb38df02",
    "X-B3-Traceid": "ab8d22984d582866ae0aef19cb38df02",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-Decorator-Operation": "httpbin.org:80/*",
    "X-Envoy-Internal": "true",
    "X-Envoy-Peer-Metadata": "ChQKDkFQUF9DT05UQUlORVJTEgIaAAoaCgpDTFVTVEVSX0lEEgwaCkt1YmVybmV0ZXMKHAoMSU5TVEFOQ0VfSVBTEgwaCjEwLjEwLjAuMjIKGQoNSVNUSU9fVkVSU0lPThIIGgYxLjE3LjgKnAMKBkxBQkVMUxKRAyqOAwodCgNhcHASFhoUaXN0aW8taW5ncmVzc2dhdGV3YXkKEwoFY2hhcnQSChoIZ2F0ZXdheXMKFAoIaGVyaXRhZ2USCBoGVGlsbGVyCjYKKWluc3RhbGwub3BlcmF0b3IuaXN0aW8uaW8vb3duaW5nLXJlc291cmNlEgkaB3Vua25vd24KGQoFaXN0aW8SEBoOaW5ncmVzc2dhdGV3YXkKGQoMaXN0aW8uaW8vcmV2EgkaB2RlZmF1bHQKMAobb3BlcmF0b3IuaXN0aW8uaW8vY29tcG9uZW50EhEaD0luZ3Jlc3NHYXRld2F5cwoSCgdyZWxlYXNlEgcaBWlzdGlvCjkKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSFhoUaXN0aW8taW5ncmVzc2dhdGV3YXkKLwojc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtcmV2aXNpb24SCBoGbGF0ZXN0CiIKF3NpZGVjYXIuaXN0aW8uaW8vaW5qZWN0EgcaBWZhbHNlChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAouCgROQU1FEiYaJGlzdGlvLWluZ3Jlc3NnYXRld2F5LTk5NmJjNmJiNi1waDI2aAobCglOQU1FU1BBQ0USDhoMaXN0aW8tc3lzdGVtCl0KBU9XTkVSElQaUmt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9pc3Rpby1zeXN0ZW0vZGVwbG95bWVudHMvaXN0aW8taW5ncmVzc2dhdGV3YXkKFwoRUExBVEZPUk1fTUVUQURBVEESAioACicKDVdPUktMT0FEX05BTUUSFhoUaXN0aW8taW5ncmVzc2dhdGV3YXk=",
    "X-Envoy-Peer-Metadata-Id": "router~10.10.0.22~istio-ingressgateway-996bc6bb6-ph26h.istio-system~istio-system.svc.cluster.local"
  }
}

 

  • 응답에서 X-B3-Traceid, X-B3-Spanid, X-B3-Sampled 같은 Zipkin 헤더가 자동으로 추가된 것을 확인할 수 있습니다.
    이 헤더들은 Jaeger로 전송되어 요청의 Span을 생성합니다.

Istio는 OpenTracing 헤더를 자동으로 주입해 분산 추적을 지원하며,
이를 외부 서비스 호출로 테스트할 수 있습니다.


📌 핵심 요약

  • 설치 시 설정: IstioOperator를 사용해 설치 시 Zipkin, Jaeger 등의 추적 백엔드를 글로벌 메쉬에 설정할 수 있습니다.
  • MeshConfig 수정: 설치 후 istio ConfigMap의 MeshConfig를 수정해 추적 설정을 변경할 수 있습니다.
  • 워크로드별 설정: Deployment 어노테이션을 통해 특정 워크로드에만 추적 설정을 적용할 수 있습니다.
  • 헤더 확인: Istio는 x-b3-* Zipkin 헤더를 자동으로 주입하며, 이를 외부 서비스 호출로 확인할 수 있습니다.
  • Istio의 분산 추적은 마이크로서비스 환경에서 요청 흐름을 추적하는 데 유용하며, 글로벌 또는 워크로드별로 유연하게 설정할 수 있습니다.

🔍 Istio 분산 추적 데이터 확인하기

Istio를 통해 생성된 분산 추적 데이터(Trace와 Span)를 확인하려면 Jaeger와 같은 OpenTracing 엔진의 UI를 활용할 수 있습니다. 


🖥️ Jaeger UI로 추적 데이터 조회하기

  • Jaeger는 Istio에서 생성된 Trace와 Span을 시각적으로 확인할 수 있는 강력한 도구입니다.
  • 이제 브라우저에서 http://localhost:30004에 접속하면 Jaeger UI를 볼 수 있습니다. 
  • Jaeger UI에 접속한 후, 다음 단계를 따라 추적 데이터를 확인합니다.
    • Services 드롭다운 메뉴에서 istio-ingressgateway를 선택합니다.
    • 화면 왼쪽 하단의 Find Traces 버튼을 클릭합니다.

  • Jaeger UI에서 istio-ingressgateway 서비스를 선택해 클러스터로 들어온 요청의 추적 데이터를 확인합니다.

  • 각 Trace를 클릭하면 해당 Trace를 구성하는 개별 Span의 세부 정보를 확인할 수 있습니다.

Jaeger UI를 통해 Istio의 추적 데이터를 시각적으로 확인할 수 있으며,
istioctl dashboard jaeger 명령어로 쉽게 로컬에서 접속 가능합니다.


⚠️ 추적 데이터가 보이지 않을 때

  • Jaeger UI에서 기대한 만큼의 Trace가 표시되지 않거나 아예 보이지 않을 수 있습니다. 이는 추적 데이터 수집 범위(trace-collection aperture)와 관련이 있습니다. Istio의 샘플링 비율(sampling rate)이 낮게 설정되어 있으면 모든 요청이 추적되지 않을 수 있습니다. Istio의 demo profile은 기본적으로 샘플링 비율을 100%로 설정해 모든 요청을 추적합니다. 

추적 데이터가 보이지 않을 경우, 샘플링 비율 또는 트래픽 부족이 원인일 수 있습니다.
Demo profile은 기본적으로 100% 샘플링을 제공합니다.


📡 추적 헤더 전파하기

  • 분산 추적 시스템이 제대로 작동하려면, 애플리케이션이 Zipkin 추적 헤더를 올바르게 전파(propagate)해야 합니다.
  • Istio 프록시는 자동으로 헤더를 주입하지만, 애플리케이션 코드가 이를 유지하고 후속 요청에 포함시켜야 합니다. 필요한 Zipkin 헤더는 다음과 같습니다.
    • x-request-id
    • x-b3-traceid
    • x-b3-spanid
    • x-b3-parentspanid
    • x-b3-sampled
    • x-b3-flags
    • x-ot-span-context
  • 애플리케이션은 요청을 처리할 때 이 헤더들을 저장하고, 외부로 보내는 모든 요청(예: 다른 서비스 호출)에 이 헤더들을 포함해야 합니다. Istio 프록시는 이를 자동으로 처리하지 않으므로, 애플리케이션 코드에서 명시적으로 구현해야 합니다.
  • 예를 들어, 애플리케이션이 HTTP 요청을 받으면:
    • 위 헤더들을 추출해 저장합니다.
    • 다른 서비스로 요청을 보낼 때 저장된 헤더를 HTTP 헤더에 추가합니다.
  • 이 과정을 생략하면 Trace가 끊겨 Jaeger에서 전체 요청 흐름을 추적할 수 없습니다.

애플리케이션은 Zipkin 추적 헤더를 반드시 전파해야 하며,
이는 Istio 프록시가 자동으로 처리하지 않는 부분입니다.


📌 핵심 요약

  • Jaeger UI 접속: istioctl dashboard jaeger 명령어로 Jaeger UI를 로컬에서 열고, istio-ingressgateway 서비스를 선택해 추적 데이터를 확인할 수 있습니다.
  • 트래픽 생성: 추적 데이터가 없으면 curl로 샘플 요청을 보내 Trace를 생성하세요.
  • 샘플링 비율: 추적 데이터가 누락될 경우 샘플링 비율을 확인해야 하며, demo profile은 100% 샘플링을 제공합니다.
  • 헤더 전파: 애플리케이션은 x-b3-* 같은 Zipkin 헤더를 저장하고 후속 요청에 포함시켜야 분산 추적이 올바르게 작동합니다.
  • Istio의 분산 추적은 Jaeger UI를 통해 시각적으로 확인할 수 있으며, 애플리케이션의 헤더 전파가 필수적입니다.

🚀 Istio에서 추적 샘플링과 커스터마이징

  • Istio의 분산 추적은 마이크로서비스 환경에서 요청 흐름을 추적하는 데 유용하지만, 성능 부담을 줄이기 위해 샘플링 비율을 조정하거나 특정 요청에 대해 추적을 강제할 수 있습니다. 또한, 커스텀 태그와 백엔드 설정을 통해 추적 데이터를 더 풍부하게 만들 수 있습니다. 

⚙️ 메쉬 전체의 추적 샘플링 조정

  • 분산 추적은 시스템 성능에 부담을 줄 수 있으므로, 샘플링 비율(sampling rate)을 조정해 추적 빈도를 제어할 수 있습니다. Istio의 demo profile은 기본적으로 100% 샘플링을 설정하지만, 이를 낮춰 성능을 최적화할 수 있습니다.
    글로벌 샘플링 비율은 istio-system 네임스페이스의 istio ConfigMap에서 수정할 수 있습니다.
  • 다음 명령어로 ConfigMap을 편집합니다.
    tracing 섹션을 다음과 같이 수정해 샘플링 비율을 10%로 설정합니다
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ KUBE_EDITOR="vi" k
ubectl edit -n istio-system cm istio
configmap/istio edited

apiVersion: v1
data:
  mesh: |-
    defaultConfig:
      discoveryAddress: istiod.istio-system.svc:15012
      proxyMetadata: {}
      tracing:
        sampling: 10
        zipkin:
          address: zipkin.istio-system:9411
    enablePrometheusMerge: true
    rootNamespace: istio-system
    trustDomain: cluster.local
  meshNetworks: 'networks: {}'
  • 이 설정은 메쉬 전체 워크로드에 대해 요청의 10%만 추적합니다.

ConfigMap의 tracing.sampling 값을 수정해 메쉬 전체의 추적 샘플링 비율을 조정할 수 있습니다.


🛠️ 워크로드별 샘플링 설정

  • 글로벌 설정 대신 특정 워크로드에만 샘플링 비율을 적용하고 싶다면, Deployment의 Pod 템플릿에 어노테이션을 추가합니다. 아래는 샘플링 비율을 10%로 설정한 예제입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/webapp-deployment-zipkin.yaml
---
apiVersion: apps/v1
kind: Deployment
...
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |
          tracing:
            sampling: 10
            zipkin:
              address: zipkin.istio-system:9411
...

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -f ch8/webapp-deployment-zipkin.yaml -n istioinaction
deployment.apps/webapp configured
  • 이를 통해 특정 워크로드에만 원하는 샘플링 비율을 설정할 수 있습니다.

워크로드별 샘플링은 Deployment 어노테이션을 통해 세밀하게 설정할 수 있습니다.


🔍 클라이언트에서 강제 추적 활성화

  • 운영 환경에서는 샘플링 비율을 낮게 유지하다가, 문제가 발생한 특정 요청에 대해 추적을 강제로 활성화하고 싶을 때가 있습니다. Istio는 x-envoy-force-trace 헤더를 사용해 특정 요청에 대한 추적을 강제할 수 있습니다.
  • 다음은 샘플 애플리케이션에서 강제 추적을 테스트하는 명령어입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ curl -s -H "x-envoy-force-trace: true" http://webapp.istioinaction.io:30000/api/catalog -v
* Host webapp.istioinaction.io:30000 was resolved.
* IPv6: (none)
* IPv4: 127.0.0.1
*   Trying 127.0.0.1:30000...
* Connected to webapp.istioinaction.io (127.0.0.1) port 30000
> GET /api/catalog HTTP/1.1
> Host: webapp.istioinaction.io:30000
> User-Agent: curl/8.5.0
> Accept: */*
> x-envoy-force-trace: true
>
< HTTP/1.1 200 OK
< content-length: 357
< content-type: application/json; charset=utf-8
< date: Tue, 29 Apr 2025 05:10:47 GMT
< x-envoy-upstream-service-time: 8
< server: istio-envoy
< x-request-id: 681a335f-64cd-a478-bdc5-f243d2927e68
<
* Connection #0 to host webapp.istioinaction.io left intact
[{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}]

  • 이 헤더를 포함하면 해당 요청과 관련된 전체 호출 그래프(call graph)에 대한 Trace와 Span이 강제로 수집됩니다.
    이를 활용해 API 게이트웨이나 진단 도구에서 특정 요청을 추적할 수 있습니다.

x-envoy-force-trace 헤더를 사용해 특정 요청에 대해 강제로 추적을 활성화할 수 있습니다.


🏷️ 추적에 커스텀 태그 추가

  • 커스텀 태그는 Span에 애플리케이션 또는 조직별 메타데이터를 추가하는 방법입니다.
    태그는 키-값 쌍으로, 추적 데이터의 필터링이나 분석에 유용합니다.
    Istio는 세 가지 방식으로 커스텀 태그를 설정할 수 있습니다.
    • 명시적 값 지정
    • 환경 변수에서 값 가져오기
    • 요청 헤더에서 값 가져오기
  • 아래는 webapp 서비스의 Deployment에 커스텀 태그를 추가하는 예제입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/webapp-deployment-zipkin-tag.yaml
---
apiVersion: apps/v1
kind: Deployment
...
  template:
    metadata:
      annotations:
        proxy.istio.io/config: |
          tracing:
            sampling: 100
            customTags: #트레이스 스팬에 추가할 사용자 정의 태그를 정의
              custom_tag:
                literal: #태그의 값을 리터럴 문자열로 지정
                  value: "Test Tag" 
                  #custom_tag의 값은 "Test Tag"라는 문자열로 설정됩니다. 
                  #이제 이 파드에서 생성되는 모든 트레이스 스팬에 custom_tag: "Test Tag"라는 태그가 포함
            zipkin:
              address: zipkin.istio-system:9411
...
  • 이 설정을 적용하려면 다음 명령어를 실행합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f ch8/webapp-deployment-zipkin-tag.yaml
deployment.apps/webapp configured
  • 트래픽을 생성해 추적 데이터를 확인합니다.
for in in {1..10}; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; sleep 0.5; done

  • Jaeger UI에서 최근 Trace를 찾아 webapp 서비스의 Span을 클릭하면, Tags 항목에 custom_tag: Test Tag가 표시됩니다.
  • 특정 Trace를 클릭해 Span 상세 정보를 확인합니다.  Span을 확장하면 커스텀 태그를 포함한 세부 정보가 표시됩니다


커스텀 태그는 Span에 메타데이터를 추가해 추적 데이터의 가치를 높이며,
Deployment 어노테이션으로 설정할 수 있습니다.


🔧 백엔드 추적 엔진 커스터마이징

  • Istio는 Zipkin, Jaeger 같은 추적 백엔드를 기본 설정으로 쉽게 연결하지만, 더 세밀한 튜닝이 필요할 때가 있습니다.
    예를 들어, Jaeger의 특정 엔드포인트(기본값: /api/v2/spans)를 변경하거나 JSON 형식을 조정할 수 있습니다.
    이를 위해 커스텀 부트스트랩(bootstrap) 설정을 사용합니다.
  • 다음 명령어로 기본 추적 설정을 확인합니다(requires jq tool).
(⎈|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:/# istioctl pc bootstrap -n istioinaction deploy/webapp -o json | jq .bootstrap.tracing
{
  "http": {
    "name": "envoy.tracers.zipkin",
    "typedConfig": {
      "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
      "collectorCluster": "zipkin",
      "collectorEndpoint": "/api/v2/spans",
      "traceId128bit": true,
      "sharedSpanContext": false,
      "collectorEndpointVersion": "HTTP_JSON"
    }
  }
}
  • 기본 엔드포인트를 /zipkin/api/v1/spans로 변경하려면, ConfigMap에 커스텀 부트스트랩 설정을 정의합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/istio-custom-bootstrap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: istio-custom-zipkin
data:
  custom_bootstrap.json: |
    {
      "tracing": {
        "http": { #HTTP 트래픽에 대한 트레이싱 설정을 정의
          "name": "envoy.tracers.zipkin",
          "typedConfig": { #트레이서 플러그인의 구체적인 설정을 정의
            "@type": "type.googleapis.com/envoy.config.trace.v3.ZipkinConfig",
            "collectorCluster": "zipkin", #트레이스 데이터를 전송할 Zipkin 콜렉터의 Envoy 클러스터 이름을 zipkin으로 지정
            "collectorEndpoint": "/zipkin/api/v1/spans", #Zipkin 콜렉터의 API 엔드포인트를 /zipkin/api/v1/spans로 설정
            "traceId128bit": "true", #128비트 트레이스 ID를 사용하도록 설정
            "collectorEndpointVersion": "HTTP_JSON" #Zipkin 콜렉터 엔드포인트의 버전을 HTTP JSON 형식으로 지정
          }
        }
      }
    }
  • 이 ConfigMap을 적용합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f ch8/istio-custom-bootstrap.yaml
configmap/istio-custom-zipkin created

(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl get cm -n istioinaction
NAME                  DATA   AGE
istio-ca-root-cert    1      24h
istio-custom-zipkin   1      13s
kube-root-ca.crt      1      24h
  • 다음으로, Deployment의 Pod 템플릿에 어노테이션을 추가해 이 ConfigMap을 참조합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ cat ch8/webapp-deployment-custom-boot.yaml
---
apiVersion: apps/v1
kind: Deployment
...
  template:
    metadata:
      annotations:
        sidecar.istio.io/bootstrapOverride: "istio-custom-zipkin"
        proxy.istio.io/config: |
          tracing:
            sampling: 10
            zipkin:
              address: zipkin.istio-system:9411
...
  • 설정을 적용합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f ch8/webapp-deployment-custom-boot.yaml
deployment.apps/webapp configured
  • 변경된 설정을 확인하려면 다시 부트스트랩 설정을 조회합니다.
(⎈|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:/# istioctl pc bootstrap -n istioinaction deploy/webapp -o json | jq .bootstrap.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"
    }
  }
}
  • webapp 추적 시 collectorEndpoint 에 잘못된 경로 설정으로 webapp Span이 출력되지 않습니다

경고: 커스텀 부트스트랩 설정은 Envoy 프록시 버전에 의존하며, 호환성 문제가 발생할 수 있습니다. 잘못된 설정은 서비스 중단을 초래할 수 있으므로, 적용 전 철저히 테스트하세요.

  • 다음 실습을 위해 다시 설정 원복
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-QMAIJOE:~/aews-labs/istio-in-action/book-source-code-master$ kubectl apply -n istioinaction -f services/webapp/kubernetes/webapp.yaml
serviceaccount/webapp unchanged
service/webapp unchanged
deployment.apps/webapp configured

커스텀 부트스트랩 설정을 통해 추적 백엔드의 엔드포인트나 형식을 변경할 수 있지만,
이는 고급 설정으로 주의가 필요합니다.


📌 핵심 요약

  • 샘플링 조정: ConfigMap 또는 Deployment 어노테이션을 통해 메쉬 전체 또는 워크로드별로 샘플링 비율을 설정해 성능을 최적화할 수 있습니다.
  • 강제 추적: x-envoy-force-trace 헤더를 사용해 특정 요청의 추적을 강제로 활성화할 수 있습니다.
  • 커스텀 태그: Span에 메타데이터를 추가해 추적 데이터를 풍부하게 만들며, Jaeger UI에서 확인 가능합니다.
  • 백엔드 커스터마이징: 커스텀 부트스트랩 설정으로 추적 엔진의 엔드포인트를 변경할 수 있지만, Envoy 버전 호환성과 테스트가 중요합니다.
  • Istio의 추적 기능은 샘플링, 강제 추적, 태그, 백엔드 설정을 통해 유연하게 커스터마이징할 수 있습니다.