Jaeger, OpenTelemetry 활용 Kubernetes 트래픽 흐름 추적
이 포스트에서는 Kubernetes 클러스터에 OpenTelemetry Operator를 통해 Jaeger 를 배포하고, OpenTelemetry Collector와 통합하여 Pod 간의 트래픽 흐름을 추적하는 방법을 다룹니다. 클러스터 내부의 마이크로서비스 애플리케이션의 트래픽 흐름을 추적하여 병목 구간을 식별하고, 성능 개선을 위한 방향을 도출하는 데 도움을 줄 수 있습니다.
먼저 Kubernetes 클러스터에 OpenTelemetry Operator를 통해 Jaeger를 배포하는 방법을 알아보고, 데모 마이크로서비스 애플리케이션인 Online Boutique를 클러스터에 배포하도록 하겠습니다.
이후 OpenTelemetry Operator의 Auto-instrumentation을 통해 애플리케이션의 코드 변경 없이 원격 측정 데이터를 OpenTelemetry Collector로 전송하도록 설정하고, Collector가 수집한 데이터를 Jaeger로 전송하여 확인하도록 하겠습니다.
이 포스트는 Kuberenetes 클러스터에 OpenTelemetry Operator가 사전에 배포된 환경에서 진행됩니다. OpenTelemetry Operator를 클러스터에 배포하는 방법은 OpenTelemetry Operator, Collector Kubernetes 배포 가이드 포스트를 참고하세요.
또한 데모 애플리케이션, Jaeger UI 연결을 위해 사전에 배포된 NGINX Ingress Controller를 사용했습니다.
목차
1. Jaeger란?
2. Auto-instrumentation이란?
3. 버전 정보
4. Jaeger 배포
5. Kubernetes 클러스터 구성
5-1. Online Boutique 배포
5-2. OpenTelemetry Collector 구성 – 데이터 수집 및 Jaeger 전송
5-3. Auto-instrumentation 구성
6. Jaeger UI로 트래픽 흐름 추적
7. 결론
1. Jaeger 란?

Jaeger는 분산 시스템에서 서비스 간 요청 흐름을 추적하고 분석하는 오픈소스 분산 추적 시스템입니다. Cloud Native Computing Foundation(CNCF)의 졸업 프로젝트로, 마이크로서비스 아키텍처에서 서비스 간 요청이 어떻게 처리되는지를 시각화하는 데 특화되어 있습니다.
Jaeger의 주요 특징
오류 추적 및 문제 해결
분산 시스템에서 발생하는 오류를 추적하고 근본 원인을 분석하는 데 유용합니다. 어떤 서비스에서 문제가 시작되었는지, 그리고 그 영향이 시스템 전체에 어떻게 퍼지는지를 확인할 수 있습니다.
분산 서비스 호출 추적
Jaeger는 여러 서비스에 걸쳐 발생하는 요청의 흐름을 추적하여 전체 서비스 호출 체인을 시각화합니다. 이를 통해 복잡한 마이크로서비스 환경에서 요청이 어떤 경로를 따라 전달되는지 쉽게 파악할 수 있습니다.
성능 및 지연 시간 분석
서비스 간 호출의 지연 시간을 측정하고 시각화하여 성능 병목 현상을 식별하고 해결하는 데 도움을 줍니다. 각 요청 단계에서 소요된 시간을 정확히 파악할 수 있어 최적화가 필요한 부분을 빠르게 찾아낼 수 있습니다.
2. Auto-instrumentation이란?
OpenTelemetry Operator의 Auto Instrumentation은 기존 애플리케이션의 코드를 수정하지 않고 원격 측정(telemetry) 데이터를 수집할 수 있게 해주는 기능입니다. 일반적으로 애플리케이션에서 원격 측정 데이터 수집 설정을 적용하려면 OpenTelemetry SDK를 직접 코드에 삽입해야 하지만, Auto Instrumentation을 사용하면 이러한 작업 없이도 자동으로 트레이스를 수집할 수 있습니다.
OpenTelemetry Operator의 커스텀 리소스인 Instrumentation을 구성하고, Pod의 annotation을 통해 Auto-instrumentation을 적용하면 Sidecar 또는 Init Container를 통해 OpenTelemetry 에이전트가 자동으로 계측 코드(Instrumentation)를 삽입하여 원격 측정 데이터를 수집할 수 있습니다.
OpenTelemetry Operator 0.117.0 버전 기준으로 Apache HTTPD, .NET, Deno(unstable), Go, Java, Node.js, Python에 대한 Auto Instrumentation을 지원합니다.
3. 버전 정보
- Kubernetes : v1.30.3
- OpenTelemetry Operator : 0.117.0
- Jaeger : 2.3.0
4. Jaeger 배포
Kubnernetes 클러스터에 Jaeger를 배포하는 방법은 Kubernetes Operator로 배포하는 방식과, Helm Chart를 통해 배포하는 방식이 있습니다. 이 포스트에서는 Kubernetes Operator로 배포하는 방식을 사용하며, Helm Chart를 통한 배포는 Jaeger Helm Chart GitHub를 참고하세요.
Jaeger V2 버전부터, Kubernetes 클러스터에서의 배포는 Opentelemetry Operator을 통해서 배포됩니다. 따라서 Opentelemetry Operator 및 Opentelemetry Collector 배포에 필요한 cert-manager 배포가 필수적입니다.
OpenTelemetry Operator를 클러스터에 배포하는 방법은 OpenTelemetry Operator, Collector Kubernetes 배포 가이드 포스트를 참고하세요.
메모리 스토리지로 배포
Jaeger는 OpenTelemetryCollector 리소스로 클러스터에 배포됩니다.
다음 yaml 파일을 사용해 클러스터에 배포할 수 있습니다.
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: jaeger-inmemory-instance
spec:
image: jaegertracing/jaeger:latest
ports:
- name: jaeger
port: 16686
config:
service:
extensions: [jaeger_storage, jaeger_query]
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger_storage_exporter]
extensions:
jaeger_query:
storage:
traces: memstore
jaeger_storage:
backends:
memstore:
memory:
max_traces: 100000
receivers:
otlp:
protocols:
grpc:
http:
exporters:
jaeger_storage_exporter:
trace_storage: memstore
monitoring 네임스페이스에 배포를 진행했습니다.
$ kubectl apply -f jaeger.yaml -n monitoring
opentelemetrycollector.opentelemetry.io/jaeger-inmemory-instance created
$ kubectl get opentelemetrycollectors.opentelemetry.io -n monitoring
NAME MODE VERSION READY AGE IMAGE MANAGEMENT
jaeger-inmemory-instance deployment 0.117.0 1/1 46s jaegertracing/jaeger:latest managed
OpenTelemetryCollector 리소스로 배포되어 Deployment 및 Service가 자동으로 배포됩니다.
$ kubectl get all -n monitoring
NAME READY STATUS RESTARTS AGE
pod/jaeger-inmemory-instance-collector-5686846544-gfllg 1/1 Running 0 67s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jaeger-inmemory-instance-collector ClusterIP 10.108.138.23 <none> 16686/TCP,4317/TCP,4318/TCP 67s
service/jaeger-inmemory-instance-collector-extension ClusterIP 10.107.57.16 <none> 16686/TCP 67s
service/jaeger-inmemory-instance-collector-headless ClusterIP None <none> 16686/TCP,4317/TCP,4318/TCP 67s
service/jaeger-inmemory-instance-collector-monitoring ClusterIP 10.102.24.28 <none> 8888/TCP 67s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/jaeger-inmemory-instance-collector 1/1 1 1 67s
NAME DESIRED CURRENT READY AGE
replicaset.apps/jaeger-inmemory-instance-collector-5686846544 1 1 1 67s
DB 스토리지로 배포
Jaeger는 클러스터에 배포된 DB에 트레이스 데이터를 저장할 수 있습니다. DB와의 연동을 위해선 DB Pod가 서비스로 노출된 상태여야 합니다.
jaeger_storage:
backends:
some_storage:
cassandra:
connection:
servers: [<service 이름>]
...
exporters:
jaeger_storage_exporter:
trace_storage: some_storage
jaeger_storage:
backends:
some_storage:
elasticseacrh:
servers: [<service 이름>]
...
exporters:
jaeger_storage_exporter:
trace_storage: some_storage
Jaeger UI
Jaeger UI는 배포된 Service의 16686 포트를 통해 연결할 수 있습니다. 이 포스트에서는 NGINX Ingress Controller와 VirtualServer 리소스를 통해 연결하도록 구성했습니다.
jaeger-vs.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: jaeger-vs
namespace: monitoring
spec:
host: jaeger.devopssong.com
routes:
- action:
pass: jaeger
path: /
upstreams:
- name: jaeger
port: 16686
service: jaeger-inmemory-instance-collector

구성한 VirtualServer를 통해 브라우저에서 접근할 수 있습니다.
5. Kubernetes 클러스터 구성

트래픽 흐름 추적을 위한 Kubernetes 클러스터를 이미지와 같이 구성하도록 하겠습니다.
otel 네임스페이스에 마이크로서비스 애플리케이션을 배포하고, 동일한 네임스페이스에 배포된 OpenTelemetry Collector로 트레이스 데이터를 전송하도록 구성합니다. OpenTelemetry Collector로 수집한 데이터는 monitoring 네임스페이스에 배포한 Jaeger로 전송하도록 구성합니다.
5-1. Online Boutique 배포
Online Boutique는 웹 기반 전자 상거래 애플리케이션으로, 다양한 개발 언어로 구성되어 gRPC로 통신하는 데모 마이크로서비스 애플리케이션입니다.
애플리케이션을 구성하는 Pod 사이의 요청 흐름을 Jaeger UI를 통해 확인할 수 있습니다.


1. 명령어를 사용하여 파일을 다운로드합니다.
$ git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
2. 애플리케이션을 배포할 네임스페이스를 생성합니다.
$ kubectl create ns otel
namespace/otel created
3. 애플리케이션을 배포합니다.
$ kubectl apply -f microservices-demo/release/kubernetes-manifests.yaml -n otel
deployment.apps/emailservice created
service/emailservice created
serviceaccount/emailservice created
deployment.apps/checkoutservice created
service/checkoutservice created
serviceaccount/checkoutservice created
deployment.apps/recommendationservice created
service/recommendationservice created
serviceaccount/recommendationservice created
deployment.apps/frontend created
service/frontend created
service/frontend-external created
serviceaccount/frontend created
deployment.apps/paymentservice created
service/paymentservice created
serviceaccount/paymentservice created
deployment.apps/productcatalogservice created
service/productcatalogservice created
serviceaccount/productcatalogservice created
deployment.apps/cartservice created
service/cartservice created
serviceaccount/cartservice created
deployment.apps/redis-cart created
service/redis-cart created
deployment.apps/loadgenerator created
serviceaccount/loadgenerator created
deployment.apps/currencyservice created
service/currencyservice created
serviceaccount/currencyservice created
deployment.apps/shippingservice created
service/shippingservice created
serviceaccount/shippingservice created
deployment.apps/adservice created
service/adservice created
serviceaccount/adservice created
$ kubectl get po,svc -n otel
NAME READY STATUS RESTARTS AGE
pod/adservice-5b575d9444-jkk8c 1/1 Running 0 2m6s
pod/cartservice-7f7b9fc469-822px 1/1 Running 1 (85s ago) 2m7s
pod/checkoutservice-6bbccb4788-x266r 1/1 Running 0 2m9s
pod/currencyservice-795445fcb8-tzjg6 1/1 Running 0 2m6s
pod/emailservice-c498b5f8b-rcqrk 1/1 Running 0 2m9s
pod/frontend-548c468bb9-t2tx2 1/1 Running 0 2m8s
pod/loadgenerator-85757f9958-22tld 1/1 Running 0 2m7s
pod/paymentservice-6578f9dcfd-sz7dr 1/1 Running 0 2m8s
pod/productcatalogservice-5865bf7d98-2g44r 1/1 Running 0 2m8s
pod/recommendationservice-758d9b68c4-x7jch 1/1 Running 0 2m9s
pod/redis-cart-7ff8f4d6ff-hplv2 1/1 Running 0 2m7s
pod/shippingservice-65cc774694-nsnpz 1/1 Running 0 2m6s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/adservice ClusterIP 10.111.101.86 <none> 9555/TCP 2m6s
service/cartservice ClusterIP 10.106.56.107 <none> 7070/TCP 2m8s
service/checkoutservice ClusterIP 10.100.59.169 <none> 5050/TCP 2m9s
service/currencyservice ClusterIP 10.100.252.184 <none> 7000/TCP 2m7s
service/emailservice ClusterIP 10.100.26.137 <none> 5000/TCP 2m10s
service/frontend ClusterIP 10.99.80.226 <none> 80/TCP 2m9s
service/frontend-external LoadBalancer 10.97.199.91 <pending> 80:30700/TCP 2m9s
service/paymentservice ClusterIP 10.108.88.203 <none> 50051/TCP 2m8s
service/productcatalogservice ClusterIP 10.98.243.223 <none> 3550/TCP 2m8s
service/recommendationservice ClusterIP 10.99.131.215 <none> 8080/TCP 2m9s
service/redis-cart ClusterIP 10.105.67.122 <none> 6379/TCP 2m7s
service/shippingservice ClusterIP 10.102.151.122 <none> 50051/TCP 2m6s
4. NGINX Ingress Controller을 통해 연결하기 위해 frontend-external Service의 타입을 ClusterIP로 변경하고, 해당 Service로 연결되도록 VirtualServer 리소스를 생성합니다.
$ kubectl patch svc frontend-external -n otel --type='merge' -p '{"spec":{"type":"ClusterIP","ports":[{"port":80,"targetPort":80}]}}'
service/frontend-external patched
demo-vs.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: demo-vs
namespace: otel
spec:
host: demo.devopssong.com
upstreams:
- name: frontend
service: frontend-external
port: 80
routes:
- path: /
action:
pass: frontend

브라우저에서 접속 시 위와 같은 화면을 확인할 수 있습니다.
5-2. OpenTelemetry Collector 구성 – 데이터 수집 및 Jaeger 전송
otel 네임스페이스에 배포된 애플리케이션 Pod들의 트레이스 데이터를 수신하고, monitoring 네임스페이스에 배포된 Jaeger로 수집한 데이터를 전송하는 OpenTelemetry Collector를 배포합니다.
OpenTelemetry Collector의 구성 요소에 대한 설명은 OpenTelemetry Operator, Collector Kubernetes 배포 가이드 포스트를 참고하세요.
otelcol.yaml
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: otel-collector-trace
namespace: otel
spec:
mode: deployment # deployment로 collector 배포
image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector
config:
# 데이터 수신 구성 (grpc, http)
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
batch:
send_batch_size: 10000
timeout: 10s
# monitoring 네임스페이스의 Jaeger Service로 데이터 전송 설정
exporters:
debug: {}
otlp/jaeger:
endpoint: jaeger-inmemory-instance-collector.monitoring.svc.cluster.local:4317
tls:
insecure: true
service:
pipelines:
# trace 데이터를 Jaeger를 타겟으로 설정한 exporter를 통해 전송
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/jaeger, debug]
$ kubectl get opentelemetrycollectors.opentelemetry.io -n otel
NAME MODE VERSION READY AGE IMAGE MANAGEMENT
otel-collector-trace deployment 0.117.0 1/1 18s ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector managed
$ kubectl get po,svc -n otel -l app.kubernetes.io/component=opentelemetry-collector
NAME READY STATUS RESTARTS AGE
pod/otel-collector-trace-collector-588c4db9bc-zqndc 1/1 Running 0 20s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/otel-collector-trace-collector ClusterIP 10.96.36.114 <none> 4317/TCP,4318/TCP 20s
service/otel-collector-trace-collector-headless ClusterIP None <none> 4317/TCP,4318/TCP 20s
service/otel-collector-trace-collector-monitoring ClusterIP 10.101.110.235 <none> 8888/TCP 20s
5-3. Auto-instrumentation 구성
Go, Node.js, Python, Java로 구성된 Online Boutique 애플리케이션 Pod로부터 트레이스 데이터를 수집할 수 있도록 auto-instrumentation(자동 계측)을 구성하는 방법을 알아보겠습니다.
loadgenerator, cartservice Pod에는 적용하지 않습니다.
기본적으로 OpenTelemetry Operator의 Go에 대한 Auto-instrumentation은 비활성화되어 있습니다. 해당 설정을 적용하기 위해 opentelemetry-operator-controller-manager Deployment에 flag를 추가합니다.
$ kubectl edit deployments.apps -n opentelemetry-operator-system opentelemetry-operator-controller-manager
...
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: opentelemetry-operator
control-plane: controller-manager
spec:
containers:
- args:
- --metrics-addr=127.0.0.1:8080
- --enable-leader-election
- --zap-log-level=info
- --zap-time-encoding=rfc3339nano
- --enable-go-instrumentation=true
...
이후 Instrumentation 리소스를 애플리케이션 Pod가 배포된 otel 네임스페이스에 배포합니다.
trace-instrumentation.yaml
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: trace-instrumentation
spec:
exporter:
endpoint: http://otel-collector-trace-collector:4317 # 기본적으로 gRPC 프로토콜을 사용하여 OpenTelemetry Collector로 데이터 전송
# 트레이스 데이터를 다른 서비스로 전파할 때 사용하는 propagators 설정
propagators:
- tracecontext # W3C Trace Context: 트레이스 컨텍스트 정보를 전파하는 표준 프로토콜
- baggage # W3C Baggage: 트레이스 관련 추가 정보를 전파하는 표준 프로토콜
- jaeger # Jaeger: Jaeger 프로토콜을 사용하여 트레이스를 전파
# 샘플러는 트레이스를 얼마나 자주 수집할지를 설정
# 'parentbased_traceidratio'는 부모 트랜잭션에 기반하여 샘플링 비율을 결정
# 'argument'는 샘플링 비율을 나타내며, '1'은 100% 샘플링을 의미
sampler:
type: parentbased_traceidratio # 부모 트랜잭션을 기준으로 샘플링 비율을 설정하는 샘플러 타입
argument: "1" # 샘플링 비율: 1 = 100% 샘플링
# Python과 Go 언어의 OpenTelemetry Collector로 데이터를 전송하는 엔드포인트를 HTTP 프로토콜 엔드포인트로 설정
python:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector-trace-collector:4318 # Python의 OpenTelemetry Collector 엔드포인트
go:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector-trace-collector:4318 # Go의 OpenTelemetry Collector 엔드포인트
Instrumentation의 propagators, sampler 설정에서 사용할 수 있는 값은 OpenTelemetry SDK 설정 문서를 참고하세요.
$ kubectl get instrumentations.opentelemetry.io -n otel
NAME AGE ENDPOINT SAMPLER SAMPLER ARG
trace-instrumentation 169m http://otel-collector-trace-collector:4317 parentbased_traceidratio 1
기존에 OnlineBoutique 애플리케이션 배포에 사용한 kubernetes-manifests.yaml 파일을 수정합니다.
포스트에서 사용한 전체 yaml 파일은 NGINX STORE GitHub에서 확인하세요.
1. 각 Pod의 annotation을 추가하여 auto-instrumentation을 활성화합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: emailservice
labels:
app: emailservice
# 이 위치는 Deployment의 annotation 위치
spec:
selector:
matchLabels:
app: emailservice
template:
metadata:
labels:
app: emailservice
annotations:
instrumentation.opentelemetry.io/inject-python: "trace-instrumentation"
- Deployment로 배포 시 annotation을 Pod의 metadata가 아닌, Deployment의 meatdata에 추가하지 않도록 주의합니다.
- inject-python : 각 애플리케이션 환경에 맞춰 구성합니다
- .NET:
instrumentation.opentelemetry.io/inject-dotnet: "true" - Deno:
instrumentation.opentelemetry.io/inject-sdk: "true" - Go:
instrumentation.opentelemetry.io/inject-go: "true" - Java:
instrumentation.opentelemetry.io/inject-java: "true" - Node.js:
instrumentation.opentelemetry.io/inject-nodejs: "true" - Python:
instrumentation.opentelemetry.io/inject-python: "true"
- .NET:
- “trace-instrumentation” : 네임스페이스에 배포된 Instrumentation 리소스의 이름을 정의합니다.
Go 애플리케이션의 경우 실행 파일의 경로를 지정해야 합니다.
template:
metadata:
labels:
app: checkoutservice
annotations:
instrumentation.opentelemetry.io/inject-go: "trace-instrumentation"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/src/checkoutservice"
각 애플리케이션 환경에 맞춰 구성합니다. OnlineBoutique의 Go 애플리케이션은 다음과 같이 구성되어 있습니다.
- checkoutservice : /src/checkoutservice
- shippingservice : /src/shippingservice
- productcatalogservice, frontend : /src/server
2. Go 애플리케이션의 경우 auto-instrumentation이 Sidecar 형태로 구현되어, Pod의 권한 설정이 필요합니다.
spec:
serviceAccountName: frontend
# 기존 Pod 적용 설정 비활성화
#securityContext:
# fsGroup: 1000
# runAsGroup: 1000
# runAsNonRoot: true
# runAsUser: 1000
containers:
- name: server
securityContext:
runAsGroup: 1000 #
runAsNonRoot: true # Pod의 설정을 컨테이너로 이동
runAsUser: 1000 #
# 기존 컨테이너 설정
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
위와 같이 기존에 Pod 단계에 적용된 설정을 비활성화하지 않을 경우 권한 문제로 인해 Sidecar 컨테이너가 생성되지 않습니다. 기존 Pod에 적용된 설정을 비활성화하고, 컨테이너로 옮깁니다.
3. Go를 제외한 애플리케이션 컨테이너의 리소스 제한을 해제합니다. 제한이 유지될 경우 Init container의 auto-instrumentation으로 인한 성능 오버헤드로 인해 Pod가 동작하지 않을 수 있습니다.
#resources:
# requests:
# cpu: 100m
# memory: 64Mi
# limits:
# cpu: 200m
# memory: 128Mi
전체 yaml 파일은 NGINX STORE GitHub에서 확인하세요.
변경한 yaml 파일을 통해 애플리케이션을 다시 배포하면 Go 애플리케이션의 경우 Sidecar 컨테이너가 추가됩니다.
$ kubectl get po -n otel
NAME READY STATUS RESTARTS AGE
adservice-556fc48b6d-jzmf7 1/1 Running 0 117m
cartservice-7f75c74cfc-xjlcp 1/1 Running 0 121m
checkoutservice-ccdb4f964-qlp72 2/2 Running 0 117m
currencyservice-7fc4547d5f-7skn8 1/1 Running 0 121m
emailservice-6cf45dfc9b-j7674 1/1 Running 0 121m
frontend-7447695d7-nclwt 2/2 Running 1 (71m ago) 117m
loadgenerator-67fc657cc5-2r7m8 1/1 Running 0 121m
otel-collector-trace-collector-588c4db9bc-zqndc 1/1 Running 0 2d
paymentservice-5667bcccb5-j8k92 1/1 Running 0 121m
productcatalogservice-64697cf69b-5bd6q 2/2 Running 0 117m
recommendationservice-669df46c9b-kfzwn 1/1 Running 0 110m
redis-cart-7ff8f4d6ff-zvqt7 1/1 Running 0 121m
shippingservice-55879f889-rzgqx 2/2 Running 0 117m
decsribe 명령어로 Pod를 확인하면, auto-instrumentation 구성에 사용된 Init Container와 OTEL 환경 변수가 설정된 애플리케이션 컨테이너를 확인할 수 있습니다.


6. Jaeger UI로 트래픽 흐름 추적
배포한 애플리케이션에서 정상적으로 트레이스 데이터가 수집 및 전송되면, Jaeger UI로 접속 시 Service 항목에서 각 애플리케이션 이름을 확인할 수 있습니다.

Jaeger UI 화면 상단의 System Architecture 탭의 Force Directed Graph에서 원 모양의 애플리케이션 위에 커서를 올리면 연결된 애플리케이션을 확인할 수 있습니다.

System Architecture 탭의 DAG 메뉴에선 아래와 같이 구조를 확인할 수 있습니다.
각 숫자는 해당 경로를 통해 호출된 요청 수를 나타냅니다.

배포한 OnlineBoutique에서 트래픽을 발생시킨 이후, 최초 화면(Search 탭)에서 Service를 지정하고 Find Traces 버튼을 클릭하면 트레이스 정보를 확인할 수 있습니다.


애플리케이션 사이에서 발생한 요청의 흐름과 시간을 사진과 같이 확인할 수 있습니다.
Jaeger UI를 활용하면 애플리케이션 간 요청 흐름을 추적하여 서비스 장애 발생 시 문제 지점(병목 구간)을 신속히 식별할 수 있습니다. 또한, 지속적인 지연이 발생하는 서비스나 특정 경로를 분석하여 성능 개선 방향을 도출하는 데 도움을 줄 수 있습니다.
7. 결론
이번 포스트에서는 Kubernetes 클러스터에 OpenTelemetry Operator를 통해 Jaeger를 배포하고, OpenTelemetry Collector와 통합하여 Pod 간의 트래픽 흐름을 추적하는 방법을 알아봤습니다.
그리고 샘플 Online Boutique 애플리케이션을 배포하고, auto-instrumentation과 OpenTelemetry Collector을 통해 트레이스 데이터를 수집하고 Jaeger로 전송하는 방법을 알아봤습니다. 마지막으로 Jaeger UI를 통해 요청의 흐름을 어떤 식으로 확인할 수 있는지 알아봤습니다.
마이크로서비스 아키텍처에서는 애플리케이션이 여러 개의 서비스로 분리되어 있으며, 각 서비스는 서로 다른 Pod 또는 컨테이너에서 독립적으로 실행됩니다. 이러한 구조는 확장성과 유지보수성을 높이는 장점이 있지만, 서비스 간 호출 관계가 복잡해지고 장애 발생 시 원인을 추적하는 것이 어려워지는 문제를 야기합니다.
이러한 문제를 해결하기 위해 분산 트레이싱(Distributed Tracing)은 필수적인 모니터링 기법이 됩니다. Jaeger와 같은 트레이싱 솔루션을 활용하면 다음과 같은 이점을 얻을 수 있습니다.
- 서비스 간 호출 관계 및 지연 시간 분석: 서비스가 요청을 처리하는 과정에서 발생하는 응답 속도와 각 호출의 소요 시간을 시각적으로 확인할 수 있어 성능 최적화에 도움이 됩니다.
- 병목 현상 및 장애 지점 식별: 트랜잭션이 여러 마이크로서비스를 거치는 동안 지연이 발생하는 서비스나 오류가 발생한 경로를 빠르게 파악할 수 있습니다.
- 실시간 모니터링 및 디버깅 용이성: 트레이스 데이터를 실시간으로 수집하여, 배포 이후에도 서비스의 상태를 모니터링하고 문제 발생 시 신속한 대응이 가능합니다.
운영 중인 클러스터에 Jaeger와 같은 분산 추적 구성이 필요하신가요? NGINX STORE를 통해 문의해 Kubernetes 기술 지원 서비스에 대해 상담해 보세요.
댓글을 달려면 로그인해야 합니다.