안녕하세요. J4J입니다.
이번 포스팅은 open telemetry 구축 가이드, otel collector를 이용하여 메트릭, 로그, 트레이스를 통합 관리하는 방법에 대해 적어보는 시간을 가져보려고 합니다.
관련 글
Kubernetes Service Mesh 구축 가이드: Istio에 대한 이해와 Istio Operator 설치 방법
Kubernetes Service Mesh 구축 가이드: Istio에 대한 이해와 Istio Operator 설치 방법
안녕하세요. J4J입니다. 이번 포스팅은 kubernetes service mesh 구축을 위한 istio에 대한 이해와 istio operator 설치하는 방법에 대해 적어보는 시간을 가져보려고 합니다. Service Mesh kubernetes 환경에서 마이
jforj.tistory.com
Micrometer Tracing으로 Spring 애플리케이션 분산 트레이싱하기
Micrometer Tracing으로 Spring 애플리케이션 분산 트레이싱하기
안녕하세요. J4J입니다. 이번 포스팅은 micrometer tracing으로 spring 애플리케이션 분산 트레이싱하는 방법에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 애플리케이션 모니터링을 위한 Spring B
jforj.tistory.com
Window에서 Chocolately로 Helm 설치하기 & Helm 명령어 정리
Window에서 Chocolately로 Helm 설치하기 & Helm 명령어 정리
안녕하세요. J4J입니다. 이번 포스팅은 window에서 chocolately로 helm 설치하는 방법과 사용할 수 있는 명령어에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 Helm 이란? Helm 입문을 위한 기본 개
jforj.tistory.com
OpenTelemetry
open telemetry는 telemetry 데이터에 해당되는 정보들을 수집/처리/내보내기를 할 수 있는 오픈 소스 observability 프레임워크입니다.
telemetry 데이터로는 다음과 같이 3가지가 존재합니다.
- 메트릭
- 로그
- 트레이스
즉, 관측을 위해 사용될 수 있는 가장 대표적인 데이터들을 CNCF에 의해 표준화된 방식으로 수집하고 다양한 백엔드 서비스들로 내보내는 기능을 제공합니다.

open telemetry 가 등장하기 이전에도 관측을 위한 메트릭/로그/트레이스 정보들은 다양한 서비스에서 수집이 이루어지고 활용되어 왔습니다.
다만 제가 겪어 보지는 못해서 정확히 체감이 되지는 않지만, oepn telemetry가 등장하기 전 가장 큰 문제점은 서비스 별 제 각각의 활용 방식이었다고 합니다.
메트릭을 수집하는 것에서도 prometheus/micrometer 등 각 서비스들이 서로 다른 방식으로 사용되었고, 분산 트레이싱을 위해서 zipkin/jaeger 등 각 서비스들이 별도 라이브러리가 사용되며 SDK/프로토콜 구분이 모두 달랐다고 합니다.
또한 메트릭/로그 정보 들을 통해서 문제가 발생된 상황들을 인지하게 되더라도, 해당 정보들만을 이용하기에는 트레이스 정보가 부족하여 추적이 불가능한 상황들도 발생했었습니다.
그래서 등장한 것이 open telemetry입니다.
open telemetry가 등장하면서 다음과 같은 상황들이 개선될 수 있었습니다.
- 백엔드 서비스 별 서로 달랐던 SDK들이 otel 기반 통합 SDK를 사용하는 방식으로 변경
- OTLP 표준화를 통해 서로 다른 exporter 들의 포맷을 통합
- 서로 다른 수집기가 관리되던 것이 otel collector를 이용한 통합 관리
- 메트릭/로그/트레이스의 정보가 서로 통합된 데이터 제공
open telemetry 기반으로 모니터링 및 사용자 로그 추적을 위한 환경을 설정하다 보면 느껴지는 점이 딱 한 가지 있었습니다.
"단순 설정만 해도 서로 다른 서비스끼리 자동 연동 & 통합되어 기능 활용 가능"
이런 상황이 가능했던 것은 표준화된 방식이 도출되었고, 모든 백엔드 서비스들에서 표준화 방식에 맞는 활용 방식으로 변경했기 때문에 가능하다고 생각합니다.
만약 open telemetry 이전의 시대에서 분산 추적 및 관측을 위한 환경을 구축하려고 했다면, 아마도 제가 직접 각 백엔드 서비스 간 데이터 연동 & 통합을 위한 설정들을 한 땀 한땀 모두 해줬을 것 같다고 느껴지는 부분입니다.
open telemetry 기반으로 통신하는 방법은 총 2가지가 있습니다.
- gRPC
- HTTP
gRPC는 구글에서 만든 원격 프로시저 호출 방식으로 HTTP 보다 더 효율적으로 서버 간 함수를 호출하는 방식입니다.
HTTP는 우리가 아는 HTTP 이구요.
open telemetry에서는 HTTP보다 gRPC 기반의 통신을 선호하고 있습니다.
왜냐하면 HTTP로 전달되는 JSON 보다 더 경량화되며, 더 빠른 속도로 데이터 전달이 가능하기 때문입니다.
다만, gRPC를 사용하지 못하는 환경에서는 당연히 HTTP 방식이 사용되어야 합니다.
OTel Collector
otel collector는 open telemetry 기반 관측을 위한 중앙 파이프라인 컴포넌트입니다.
"Receiver > Processor > Exporter"의 순서를 거치며 telemetry 데이터 인 메트릭/로그/트레이스 정보들을 수집하고, 가공한 뒤 데이터 별 백엔드 서비스에 내보내는 역할까지 모두 수행합니다.
open telemetry 이전 각 백엔드 서비스에서 수집을 위해 사용되던 것들이 모두 합쳐진 개념으로 인지할 수 있으며, 단순하게 모든 telemetry 데이터들이 사용되기 위해 가장 먼저 데이터가 모이는 장소라고 생각할 수 있습니다.
receiver는 수집기가 어떻게 데이터를 받을 것인가를 설정하는 곳이며 대표적으로 otlp, prometheus 등이 있습니다.
otlp는 open telemetry protocol 기반으로 수집하는 것이고, prometheus도 scrape 기반으로 수집하는 것을 의미합니다.
이 외에 jaeger, zipkin 방식 등도 모두 존재하지만 이들의 설정은 otlp 이전의 방식도 모두 호환될 수 있도록 하기 위해 존재하는 것으로 알고 있습니다.
만약, otlp 기반으로만 통신이 이루어지는 환경이라면 별도로 필요하지 않습니다.
processor는 수집된 데이터를 가공 및 최적화하는 과정입니다.
대표적으로 메모리 제한 설정, 데이터를 묶어 전송하는 batch 처리, tail_sampling 기반의 sampling 필터 처리 등 이 외에도 다양한 작업을 할 수 있는 곳입니다.
이곳은 receiver, exporter의 설정과 달리 외부 백엔드 서비스들과 연계되는 곳이 아니고 otel collector 내부 처리가 이루어진다고 생각해 주시면 됩니다.
exporter는 processor에 의해 가공된 데이터들을 어디로 내보낼지 설정하는 곳입니다.
대표적으로 otlp, jaeger, debug 등이 존재합니다.
otlp는 다른 open telemetry protocol 기반의 서비스를 의미하며, jaeger는 jaeger collector를 의미합니다.
여기서 jaeger는 전통적인 방식을 의미하기도 하며, jaeger collector는 otlp로도 설정될 수 있습니다.
그리고 debug 같은 경우는 다른 서비스로 내보낸다기보다는 말 그대로 디버깅 용입니다.
처리된 데이터들을 로그로 확인하고 싶은 경우 사용될 수 있습니다.
OTel Collector 설치
이제는 클러스터 환경에서 otel collector를 설치해 보겠습니다.
helm 기반으로 설치하는 것을 권장드리며 helm을 이용한다면 다음과 같이 구성할 수 있습니다.
[ 1. helm repository 추가 ]
$ helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
$ helm repo update
[ 2. otel collector namespace 구성 ]
$ kubectl create namespace observability
[ 3. otel collector values 구성 ]
// otel-collector-values.yaml
# collector 모드 설정 (deployment, daemonset, statefulset), 중앙 집중형의 형태로 collector 사용
mode: deployment
presets:
kubernetesAttributes:
# 수집된 span에 kubernetes 메타데이터 자동 라벨 적용 (pod, namespace, node 정보 등)
enabled: true
config:
# 데이터를 내보내는 exporter 서비스 설정
exporters:
# otlp 기반 exporter (jeager 설정)
otlp:
endpoint: jaeger-collector.observability.svc:4317 # gRPC 기반 데이터 전송
tls:
insecure: true # tls 인증 생략
# collector 디버깅용 정보 출력
# 실제 운영할 땐 debug: { }로 설정 권장
debug:
verbosity: detailed
# receiver 로 부터 전달 받은 데이터를 가공하는 단계
processors:
# 여러 데이터를 한 번에 묶어서 전송하기 위한 batch 설정
batch:
# batch 크기
send_batch_size: 1024
# batch 전송 주기
timeout: 5s
# exporter를 통해 데이터가 내보내지기 전 trace sampling 처리
# 사전 sampling 처리만 필요한 경우 설정할 필요 없음
tail_sampling:
# 첫 span을 확인한 뒤 sampling 판단을 내리기 위해 기다리는 시간
decision_wait: 10s
# 메모리에 동시에 관리되는 trace 수
num_traces: 10000
# 추정되는 TPS 설정
expected_new_traces_per_sec: 100
policies:
# 에러 발생한 trace는 항상 sampling
- name: error-traces
type: status_code
status_code:
status_codes: [ERROR]
# 설정 외 모든 trace는 5%만 sampling
- name: normal-traces
type: probabilistic
probabilistic:
sampling_percentage: 5
# 동일 trace를 모으기 위한 설정
groupbytrace:
# 동일 trace가 모두 모일때까지 최대 기다리는 시간
wait_duration: 10s
# 메모리에 동시에 관리되는 trace 수
num_traces: 10000
# 메모리 제한 설정
memory_limiter:
# 메모리 제한 확인 주기
check_interval: 5s
# resource limit 메모리의 80%까지 사용 제한
limit_percentage: 80
# 갑자기 요청이 몰려 순간적으로 메모리 사용량이 치솟아도 추가로 최대 resource limit의 25%까지 허용
# limit_percentage + spike_limit_percentage 만큼 메모리가 사용될 수도 있음
spike_limit_percentage: 25
# collector에 수신될 수 있는 정보 설정
receivers:
# otlp 설정
otlp:
protocols:
# 네트워크 전역에 gRPC로 수신 가능하도록 설정
grpc:
endpoint: 0.0.0.0:4317
# 네트워크 전역에 http로 수신 가능하도록 설정
http:
endpoint: 0.0.0.0:4318
# jaeger, prometheus, zipkin 등 추가 설정 가능
service:
# Receivers → Processors → Exporters 처리 파이프라인 정의, 정의된 순서대로 동작을 수행
pipelines:
logs:
# debug 를 원하는 경우 주석 해제
# exporters:
# - debug
processors:
- memory_limiter
- batch
receivers:
- otlp
metrics:
# debug 를 원하는 경우 주석 해제
# exporters:
# - debug
processors:
- memory_limiter
- batch
receivers:
- otlp
traces:
exporters:
- otlp
- debug
processors:
- memory_limiter
- groupbytrace
- tail_sampling
- batch
receivers:
- otlp
image:
# contrib 이미지 사용, processor에 tail_sampling, groupbytrace 등 활용 하기 위함
# 가장 최소한의 설정만 담긴 collector, 클러스터 환경을 위한 collector-k8s 등 다양하게 존재
repository: otel/opentelemetry-collector-contrib
resources:
# resource limit 설정 (otel-collector가 사용할 수 있는 최대 리소스 설정)
limits:
cpu: 250m
memory: 512Mi
[ 4. otel collector 설치 ]
$ helm install otel-collector open-telemetry/opentelemetry-collector -n observability -f otel-collector-values.yaml
[ 5. otel collector 설치 확인 ]
다음 명령어를 통해 otel collector pod가 정상적으로 띄워졌는지 확인해 줍니다.
container가 정상 실행이 이루어져 있다면 문제없이 설치된 것으로 생각할 수 있습니다.
$ kubectl get pods -n observability
Istio Tracing 연동
otel collector가 설치가 완료되었다면 istio의 설정에 대해 다시 돌아봐야 합니다.
제가 이전 글에서 istio-operator를 이용하여 설치한 사항을 확인하면 단순히 istiod가 구성되고 envoy sidecar가 자동 주입되는 것들만 존재합니다.
otel collector가 설정되었다면 모든 envoy에서 생성되는 tracing 정보를 otel collector에서 수집할 수 있습니다.
이렇게 수집된 데이터는 jaeger와 같은 exporter 설정을 통해 사용자 요청 추적 정보로 사용됩니다.
"모든 설정은 이전 글에서 작성했던 istio operator 설정을 기반으로 추가 설정이 이루어집니다."
[ 1. istio-operator 설정 추가 ]
이전 글에서 작성했던 istio-operator 설정 파일에 다음과 같이 otel collector의 설정을 추가할 수 있습니다.
// istio-operator.yaml
...
spec:
# mesh 설정
meshConfig:
# tracing 활성화
enableTracing: true
# 기본 설정
defaultConfig:
tracing:
# tracing에 대한 sampling 100으로 설정 (tail sampling을 하지 않는다면 조정 필요)
sampling: 100
# access log 표준 출력 설정
accessLogFile: /dev/stdout
# envoy sidecar에 의해 trace가 전달되어야 하는 exporter 등록
extensionProviders:
- name: otel-collector
opentelemetry:
# otel collector svc 설정
service: otel-collector-opentelemetry-collector.observability.svc.cluster.local
# gRPC port 사용
port: 4317
# 기본적으로 사용될 provider 등록
defaultProviders:
tracing:
- otel-collector
[ 2. istio 재 설치 ]
$ istioctl install -f istio-operator.yaml
Tail Sampling 검증
사실 istio와 otel-collector, 그 외 telemetry와 관련된 모든 백엔드 서비스들이 아무리 잘 설정되어 있다고 하더라도 설정 방식에 따라 모든 데이터가 수집되지 않을 수 있습니다.
그리고 그 이유로 대표적인 것이 sampling이 될 수 있습니다.
sampling은 수집되는 telemetry 데이터 들 중 일정 비율만 수집될 수 있도록 도와주는 설정입니다.
그리고 sampling이 필요한 이유는 운영 단계에서 불 필요한 데이터까지 항상 수집하여 대량 데이터 처리가 이루어지는 것을 방지하여 부하를 줄이기 위함입니다.
sampling의 설정 중 가장 편리한 방식은 head sampling입니다.
사전 sampling 처리를 하는 것으로 위에서 볼 수 있었던 istio-operator의 defaultConfig.tracing.sampling 이 예시가 될 수 있습니다.
head sampling 설정을 한다면 otel collector에 전달될 때부터 정해진 비율에 해당되는 telemetry 정보만 전달이 이루어집니다.
다음으로 tail sampling이 있습니다.
사후 sampling 처리를 하는 것으로 위에서 볼 수 있었던 otel-collector의 processor에 설정된 tail_sampling 이 예시가 될 수 있습니다.
head sampling의 가장 큰 문제점 중 하나는 확률 기반 랜덤에 의해 sampling 처리가 이루어지는 것입니다.
즉, 실제로 장애 발생한 요청에 대해 추적이 필요할 때 확률에서 탈락하여 수집이 이루어지지 않게 될 수 있다는 것입니다.
tail sampling은 이러한 head sampling의 문제점을 보완하기 위해 사용됩니다.
에러가 발생한 데이터, 일정 시간 이상이 소요된 데이터들은 무조건 수집을 하고 그 외 데이터는 수집을 하지 않거나 정말 작은 비율로만 수집을 하는 설정을 할 수 있습니다.
이를 통해 서비스 별 필수적으로 수집되어야 하는 정보들을 명확히 분류하고, 실제로 추적이 필요한 상황에 항상 데이터가 수집되어 있는 상태로 유지될 수 있습니다.
이제는 otel-collector에서 tail sampling을 저와 같이 설정한 경우 실제로 의도한 사항에 맞게 수집이 이루어지는지 테스트해보겠습니다.
설치된 otel-collector의 로그를 확인해 보면 다음과 같은 정보를 확인할 수 있습니다.

이곳에 envoy sidecar에 다음과 같이 500 에러가 아닌 요청들이 이루어지더라도 otel-collector의 로그에서 확인이 되지 않는 것을 볼 수 있습니다.

하지만 이번에는 500 에러가 발생되는 요청들을 다음과 같이 연속적으로 보내보겠습니다.

그러면 tail_sampling이 수집해야 되는 설정 범위 안에 있기 때문에 otel-collector에서 trace 정보가 확인되는 것을 볼 수 있습니다.

Spring Boot Otlp Exporter 설정
위에서 설정했던 istio tracing 연동 같은 경우 네트워크 계층에서 발생된 tracing 정보들이 otel collector로 수집되는 설정들이 담겨 있습니다.
하지만 istio의 설정은 실제 동작이 이루어지는 애플리케이션이 아닌 인프라 레벨에서 확인하는 정보이기 때문에 애플리케이션 내부에서 발생된 tracing 정보에 대해서는 알 수 없습니다.
그래서 애플리케이션 내부의 동작에 대한 설정도 알고 싶다면 애플리케이션 내부에 otel collector로 telemetry 데이터를 전송하는 설정이 담겨 있어야 합니다.
대표적으로 spring boot를 이용하여 설정을 해보겠습니다.
spring boot를 이용하여 설정하게 된다면 istio 설정만으로 확인할 수 없는 다음과 같은 정보들이 otel collector에 수집될 수 있습니다.
- 호출된 메서드 정보
- 사용된 DB 정보
- Exception 정보
- 등등
즉, 네트워크 계층에서는 절대 확인되지 못하는 애플리케이션 만의 고유 정보들이 함께 담겨 있기 때문에 장애가 발생한 경우 더 디테일한 tracing 정보가 필요하다면 애플리케이션 내부 otlp exporter 설정이 필수라고 얘기할 수 있습니다.
spring boot를 이용한 otlp exporter 설정은 다음과 같이 할 수 있습니다.
[ 1. dependency 설정 ]
// build.gradle
dependencies {
// actuator 설정
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// open telemetry tracing bridge 설정
implementation 'io.micrometer:micrometer-tracing-bridge-otel'
// open telemetry exporter 설정
implementation 'io.opentelemetry:opentelemetry-exporter-otlp'
}
[ 2. application resource 설정 ]
// application.yml
management:
tracing:
# tracing에 대한 sampling 100으로 설정 (tail sampling을 하지 않는다면 조정 필요)
sampling:
probability: 1.0
otlp:
# tracing 정보 exporter 설정
# gRPC 기반 설정은 지원되지 않아서 HTTP 기반 설정
tracing:
endpoint: http://otel-collector-opentelemetry-collector.observability.svc.cluster.local:4318/v1/traces
위의 설정의 경우 해당 애플리케이션이 otel collector와 동일한 클러스터 내부에 담겨 있다는 가정하게 적용할 수 있습니다.
단순 설정 추가만으로도 otel collector에 수집되는 데이터에서 다음의 정보들이 추가 수집되고 있는 것을 확인할 수 있습니다.

이상으로 open telemetry 구축 가이드, otel collector를 이용하여 메트릭, 로그, 트레이스를 통합 관리하는 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Infra, Cloud > Kubernetes' 카테고리의 다른 글
| OpenTelemetry Operator로 Java Agent 자동 주입하기, 코드 수정 없는 Trace 수집 (0) | 2025.11.11 |
|---|---|
| Jaeger Operator를 구축하여 Trace 시각화하기, OpenTelemetry 연동 가이드 (0) | 2025.11.04 |
| Istio Metric을 Prometheus로 수집하기, ServiceMonitor/PodMonitor 활용 (0) | 2025.10.19 |
| Kubernetes Service Mesh 구축 가이드, Istio에 대한 이해와 Istio Operator 설치 방법 (0) | 2025.10.12 |
| Grafana Alert Rule을 활용한 Slack 알림 설정 가이드 (0) | 2025.09.22 |
댓글