안녕하세요. J4J입니다.
이번 포스팅은 open telemetry operator로 java agent를 자동 주입하여 코드 수정 없이 trace 수집하는 방법에 대해 적어보는 시간을 가져보려고 합니다.
관련 글
OpenTelemetry 구축 가이드: OTel Collector를 이용하여 메트릭, 로그, 트레이스를 하나로
OpenTelemetry 구축 가이드: OTel Collector를 이용하여 메트릭, 로그, 트레이스를 하나로
안녕하세요. J4J입니다. 이번 포스팅은 open telemetry 구축 가이드, otel collector를 이용하여 메트릭, 로그, 트레이스를 통합 관리하는 방법에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 Kubernet
jforj.tistory.com
Jaeger Operator를 구축하여 Trace 시각화하기: OpenTelemetry 연동 가이드
Jaeger Operator를 구축하여 Trace 시각화하기: OpenTelemetry 연동 가이드
안녕하세요. J4J입니다. 이번 포스팅은 jaeger operator를 구축하여 trace 시각화하는 방법에 대해 적어보는 시간을 가져보려고 합니다. 관련 글 OpenTelemetry 구축 가이드: OTel Collector를 이용하여 메트릭,
jforj.tistory.com
OpenTelemetry Java Agent
java agent는 동적으로 바이트 코드를 주입하여 라이브러리와 프레임워크에서 telemetry 정보들을 수집할 수 있도록 도와줍니다.
jvm 옵션 값을 이용하여 주입될 수 있고, 주입된 java agent가 있는 경우 클래스를 실행 시점에 가로챈 뒤 telemetry 정보들인 metric, log, trace 정보들을 자동으로 수집하고 otel collector와 같은 exporter에 전달까지 해줍니다.
그리고 java agent는 마치 sidecar container와 유사한 방식으로 동작이 이루어집니다.
관측을 위해 제가 계속 작성하고 있는 이전 글들을 계속 읽어오신 분들은 java agent를 꼭 사용해야 하는 의문이 들 수 있습니다.
왜냐하면 spring boot 기준으로, 애플리케이션 내부 resource 파일에 micrometer 기반의 exporter 설정을 통해 telemetry 정보들을 전달할 수 있기 때문입니다.
하지만 java agent를 사용하는 가장 큰 장점은 관리하는 모든 애플리케이션 서비스에 독립적이며 단순한 설정을 통해 광범위한 telemetry 정보들을 수집할 수 있는 것이라고 생각합니다.
java agent가 주입된 경우 다음과 같은 telemetry 데이터들이 자동 수집이 이루어집니다.
- HTTP 통신 (요청/응답)
- JPA 사용 (JPARepository 등)
- Database 통신 (Connection 정보, 호출된 Database Query 등)
- Kafka 통신 (Producer/Consumer)
- Redis 통신 (캐싱 처리, 정보 조회 등)
- RestTemplate/WebClient 기반 외부 통신
- 등등...
애플리케이션 내부에 별도 작업을 하지 않더라도 애플리케이션의 주요 동작에 사용되는 정말 많은 데이터들을 자동 계측을 해줍니다.
반대로, 이런 정보들을 java agent 없이 micrometer 만을 가지고 모두 수집하고 싶다면 설정이 불가능한 것도 있을뿐더러 수동으로 설정해줘야 하는 것들이 정말 다양하게 존재합니다.
또한 MSA 기반의 서비스들이 많이 등장하는 요즘 시대에서 모든 애플리케이션 서비스가 각 수동 설정을 넣는 것보다는 단순 딸깍 수준의 java agent 주입을 사용하는 것이 관리적인 측면에서도 더 효과적이라고 생각됩니다.
번외로 open telemetry agent는 java만 존재하지는 않습니다.
OpenTelemetry ZeroCode 계측 공식 문서를 확인해보면 javascript, python 등 우리가 자주 사용하는 언어들에 대한 것들도 함께 지원하고 있으니 참고해 주시면 될 것 같습니다.
Zero-code Instrumentation
OpenTelemetry zero-code instrumentation is supported for the languages listed below in the section index. If you are using Kubernetes, you can use the OpenTelemetry Operator for Kubernetes to inject zero-code instrumentation for .NET, Java, Node.js, Python
opentelemetry.io
Micrometer와의 개념적 차이
java agent를 사용하기 위해서는 결국 micrometer와의 개념적 차이를 이해하고 넘어가는 것이 필요하다고 생각합니다.
위에서 얘기한 것을 이해하신 분들은 다음과 같이 생각이 들 수 있습니다.
"그냥 java agent만 주입하여 사용하면 되는거 아님 ??"
물론 이런 생각도 틀리다고는 말할 수 없습니다.
왜냐하면 java agent만 있어도 정말 많은 유형의 telemetry 데이터 정보들을 수집할 수 있기 때문입니다.
하지만 제가 가장 권장하는 방법은 java agent와 micrometer를 함께 사용하는 것입니다.
이유로는 다음과 같이 표로 얘기를 해볼 수 있습니다.
| Java Agent | Micrometer | |
|---|---|---|
| 계측 위치 | 클래스 실행 시점 전/후 | 애플리케이션 비즈니스 내부 |
| 계측 범위 | JPA, JDBC, HTTP, Redis, Kafka 등 | 비즈니스 로직 계층 |
| 애플리케이션 내부 접근 가능 여부 | 불가능 | 가능 |
| 데이터 수집 깊이 | 라이브러리 내부 호출 까지 | 비즈니스 로직 단위 |
즉, 이곳에서 말하고자 하는 것은 java agent는 애플리케이션 내부까지 접근이 불가능하다는 것입니다.
그래서 애플리케이션 내부에 정의되어 있는 비즈니스 로직 별 원하는 telemetry 정보들을 커스터마이징하여 수집하고 싶다면 micrometer가 함께 사용되어야 합니다.
하지만 함께 사용하는 경우 다음과 같이 주의해야 하는 사항이 있습니다.
[ 대표 관측자 정의 ]
java agent와 micrometer를 모두 사용하는 경우 대표 관측자를 정의해야 합니다.
왜냐하면 java agent에 의해 수집되는 span 정보들이 micrometer를 통해서도 수집이 될 수 있기 때문입니다.
중복 span이 수집되어 버린다고 잘못되는 것은 아니지만, 통합 span을 확인할 때 동일한 유형의 span이 연속적으로 보이는 결과를 만들 수 있습니다.
이런 상황에 노출되면 추적을 시도할 때 올바른 추적을 하기에는 중복된 값들을 분류하는 작업이 필요할 수 있습니다.
일반적으로 대표 관측자는 java agent를 사용하는 것으로 보입니다.
[ 중복 수집 데이터 제거 ]
위에서 얘기한 것처럼 중복 수집 데이터들을 확인하고 제거하는 과정이 필요하며, 대표적으로 java agent와 micrometer 모두 HTTP 통신에 대한 데이터를 수집하는 것을 얘기할 수 있습니다.
중복 적재가 발생하는 데이터들은 대표 관측자를 통해서만 적재할 수 있도록 설정하며, 대표 관측자가 아닌 곳은 데이터가 수집되지 않도록 설정을 제거해 주는 것이 필요합니다.
그래서 대표 관측자가 아닌 곳은 추가적인 설정을 통해 중복되어 적재되는 것을 방지하는 과정이 필요하며, 이 설정들은 프로젝트에서 사용되는 것들이 무엇이 있는지에 따라 설정의 범위가 달라지게 됩니다.
중복으로 발생되는 정보로는 HTTP 요청/응답 정보, Kafka, Datasource 등의 정보들이 존재하는 것으로 보입니다.
OpenTelemetry Operator Java Agent 주입 환경 구축
open telemetry operator는 kubernetes 환경에서 collector와 자동 계측을 포함한 open telemetry 구성 요소들을 자동으로 배포 및 관리해 주는 컨트롤러입니다.
각각의 구성요소들을 별도로 설정할 수도 있지만 operator를 사용하게 된다면 open telemetry를 위한 CRD를 이용하여 더욱 편리하게 설정할 수 있도록 기능들을 제공합니다.
특히 java agent를 사용할 때 가장 단순한 방법 중 하나는 java 런타임 단계 때 다음과 같은 옵션을 추가하여 agent 실행하는 방식이 존재합니다.
java -javaagent:/otel/opentelemetry-javaagent.jar \
-Dotel.service.name=myapp \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
-jar myapp.jar
어렵지 않은 방식이기에 일반적으로 많이 사용될 수 있지만, kubernetes 기반의 정말 다양한 애플리케이션 서비스를 운영하고 있다면 모든 java 런타임에 해당 옵션 값을 추가하고 agent.jar 파일을 관리하는 것은 끔찍한 일이 될 수 있습니다.
이때 open telemetry operator를 이용한 설정을 하게 된다면 deployment 리소스의 metadata 정보 추가로 자동 주입을 할 수 있도록 도와줍니다.
그러면 매번 각 서비스들의 런타임 단계 때 사용되는 옵션과 agent 파일들을 관리할 필요가 없어지며 동일한 kubernetes 내부에 있는 서비스라면 언제든지 쉽게 agent를 사용하는 환경이 구축될 수 있습니다.
이제는 open telemetry operator를 설치한 뒤 java agent 주입을 할 수 있는 환경을 구축해 보겠습니다.
[ 1. cert manager 설치 ]
이전 글에서 jaeger operator를 구성할 때 jaeger 서비스 간 안전한 통신을 위해 cert manager를 필수적으로 구성해야만 했습니다.
open telemetry operator도 동일한 이유로 cert manager를 필수적으로 설치해줘야 합니다.
다만, 기존에 구성되어 있는 cert manager가 있는 경우에는 보통 추가적인 설치를 별도로 수행하지 않아도 됩니다.
cert manager의 최신 release 버전은 CertManager Release에서 확인할 수 있습니다.
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml
[ 2. open telemetry operator 설치 ]
open telemetry operator의 최신 release 버전은 OpenTelemetryOperator Release에서 확인할 수 있습니다.
$ kubectl create namespace opentelemetry-operator-system
$ kubectl create -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml -n opentelemetry-operator-system
[ 3. instrumentation 구성 ]
instrumentation은 자동 계측을 위해 agent들을 관리하기 위한 설정이 담긴 리소스입니다.
이곳에서 필요로 하는 모든 개발 언어들의 agent 설정들을 적용할 수 있으며, 한 번의 설정으로 모든 언어의 agent 주입 방식에 대한 정의를 할 수 있습니다.
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: auto-instrumentation
namespace: observability
spec:
# tracing 정보 exporter 설정
exporter:
endpoint: http://otel-collector-opentelemetry-collector.observability.svc.cluster.local:4318
# context 전파자 설정, trace 정보를 다음 서비스로 넘기는 규약
propagators:
- tracecontext
- baggage
- b3
# sampling 설정
sampler:
type: parentbased_traceidratio
argument: "1" # 100% sampling 처리
# java image 최신 버전 적용
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.21.0
# 더 많은 언어 버전이 필요한 경우 추가 구성
# python:
# image:
# nodejs:
# image:
# 공통 레이블 설정 정보가 필요한 경우 추가 구성
# resource:
# attributes:
# deployment.environment: "development"
[ 4. instrumentation 설치 ]
$ kubectl apply -f instrumentation.yaml
[ 5. 설치 확인 ]
$ kubectl get instrumentation -n observability
[ 6. 애플리케이션 서비스 deployment metadata 주입 ]
apiVersion: apps/v1
kind: Deployment
...
spec:
...
template:
metadata:
...
annotations:
# java agent 주입
# 동일한 namespace에 있는 instrumentation이 하나만 있는 경우 "true"
# 동일한 namespace에 있는 여러 개 중 특정 instrumentation을 적용하고 싶은 경우 "{instrumentation 명}"
# 다른 namespace에 있는 instrumentation을 적용하고 싶은 경우 "{namespace}/{instrumentation 명}"
instrumentation.opentelemetry.io/inject-java: "observability/auto-instrumentation"
spec:
containers:
...
[ 7. java agent 주입 후 jaeger ui 확인 ]
java agent가 올바르게 주입이 이루어졌다면 클래스 실행 시점에 요청을 가로챈 뒤 자동으로 telemetry 정보가 수집되어 micrometer 기반으로 수집하는 것보다 더 많은 span 정보를 확인할 수 있게 됩니다.
간단한 테스트로 아래처럼 사용자의 요청이 처리될 때 접근되었던 JPA, Database 등에 대한 정보들이 jaeger ui에서 확인되는 것을 볼 수 있습니다.

그중 select 처리가 이루어진 span을 확인하면 query도 함께 보이는 것을 볼 수도 있습니다.

이 외에도 사용자의 요청에 의해 redis, kafka, 외부 api 호출 등도 통신이 이루어진 경우 모두 span 정보로 확인이 함께 되는 것을 경험할 수 있습니다.
Java Agent를 사용하면서 Micrometer 함께 사용하는 경우
지금까지 설정한 것처럼 java agent만 주입된 상태에서 micrometer와 관련된 설정 자체를 spring boot 내부에 하지 않는다면 java agent 만을 이용하여 telemetry 정보들이 수집될 것입니다.
하지만 만약 위에서 얘기한 것처럼 java agent와 micrometer를 함께 사용하고, 대표 관측자가 java agent인 경우를 원한다면 부가적인 설정들이 필요합니다.
여러 설정들이 필요할 수 있지만 대표적으로 설정될 수 있는 것들에 대해서 가볍게 정리해 보겠습니다.
[ open telemetry exporter 설정 ]
애플리케이션 서비스 내부에 수집된 정보들을 애플리케이션에서 바로 수집기로 전달하는 설정입니다.
애플리케이션에서 추가적으로 발생되는 span 정보들도 함께 수집되기를 원한다면 instrumentation과 동일한 exporter 설정을 해줘야 합니다.
필요 설정들은 다음과 같은 것들이 있을 수 있습니다.
// 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'
}
// application.yml
management:
observations:
annotations:
enabled: true # @Observed 기반 관측을 사용하고 싶은 경우 설정
tracing:
sampling:
probability: 1.0 # samplnig 100% 설정
otlp:
tracing:
endpoint: http://otel-collector-collector.observability.svc.cluster.local:4318/v1/traces # exporter endpoint 설정
[ 중복 수집 데이터 제거 ]
위에서 얘기한 것처럼 HTTP 통신, Kafka 통신 등 중복 적으로 자동 수집이 이루어지는 데이터들이 존재합니다.
이런 데이터들은 수집되지 않기 위해 다음과 같은 설정들을 해볼 수 있습니다.
// build.gradle
dependencies {
// datasource micrometer 설정 제거
// implementation "net.ttddyy:datasource-micrometer"
// implementation "net.ttddyy:datasource-micrometer-spring-boot"
}
// application.yml
management:
observations:
enable:
# java agent 중복 데이터 수집 대상 제거 (http / kafka)
http.server.requests: false
http.client.requests: false
spring.kafka: false
필요한 설정들이 적용되었으면 비즈니스 내부적으로 span 정보가 추가되도록 가볍게 설정을 해보겠습니다.
telemetry 데이터들을 수집하는데 편리한 @Observed를 사용해 보겠습니다.
위에서 제가 예시로 보여드렸던 jaeger ui의 결과를 만드는 controller method에 다음과 같은 어노테이션을 추가해보려고 합니다.
@Observed(name = "test_requests", contextualName = "TestController.test") // 추가 사항
@GetMapping("/test")
public ResponseEntity<Object> test() {
...
}
그리고 다시 재 배포를 한 뒤 api를 호출해 보고 jaeger의 결과를 확인해 보면 이전과 달리 agent 만 이용했을 때 수집되지 않았던 span 정보가 함께 확인되는 것을 볼 수 있습니다.

이상으로 open telemetry operator로 java agent를 자동 주입하여 코드 수정 없이 trace 수집하는 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Infra, Cloud > Kubernetes' 카테고리의 다른 글
| Istio Service Mesh 시각화, Kiali Operator 구축 가이드 (0) | 2025.11.26 |
|---|---|
| OTel Collector 이관 가이드, Helm 기반에서 OpenTelemetry Operator로 (0) | 2025.11.19 |
| Jaeger Operator를 구축하여 Trace 시각화하기, OpenTelemetry 연동 가이드 (0) | 2025.11.04 |
| OpenTelemetry 구축 가이드: OTel Collector를 이용하여 메트릭, 로그, 트레이스를 하나로 (0) | 2025.10.28 |
| Istio Metric을 Prometheus로 수집하기, ServiceMonitor/PodMonitor 활용 (0) | 2025.10.19 |
댓글