앞 글에서는 Log·Trace·Metric을 연결해야 보안 사고의 범위와 원인을 함께 볼 수 있다고 설명했다. 그렇다면 애플리케이션이 만든 세 신호는 어떤 길을 따라 관측 백엔드까지 이동할까? 이때 자주 함께 등장하는 이름이 OpenTelemetry와 Grafana Alloy다.
OpenTelemetry, 줄여서 OTel은 관측 신호를 만들고 표현하고 전달하는 벤더 중립 규격과 도구 생태계다. Grafana Alloy는 그 생태계의 Collector 배포판으로, 여러 곳에서 들어온 신호를 받아 처리한 뒤 목적지로 보내는 실행 프로그램이다. 한 문장으로 줄이면 OpenTelemetry가 공용 운송 규칙이라면 Alloy는 그 규칙을 이해하는 환승센터다.
이 글에서는 애플리케이션에서 OTLP로 신호를 보내고, Podman에서 실행한 Alloy가 이를 수신·가공·전달하는 최소 실습을 진행한다. 실습은 로컬 디버그 출력까지만 확인하며, 마지막에는 운영 환경에서 반드시 보완해야 할 보안과 장애 대응 지점도 짚는다. 제품 동작과 예시는 2026년 9월 3일 공식 문서를 기준으로 확인했다.

OpenTelemetry와 Alloy는 같은 것이 아니다
OpenTelemetry는 하나의 서버 제품이 아니다. API와 SDK, 자동 계측, 데이터 모델, Semantic Conventions, OTLP(OpenTelemetry Protocol), Collector 같은 여러 요소를 묶은 프로젝트다. 애플리케이션 SDK는 Span·Metric·Log Record를 만들고, Resource 속성으로 어느 서비스와 환경에서 나왔는지 설명하며, Trace Context로 서비스 사이의 요청 관계를 이어 준다.
OpenTelemetry Collector는 이 신호를 받는 Receiver, 변환·필터링하는 Processor, 밖으로 보내는 Exporter를 파이프라인으로 연결하는 벤더 중립 프록시다. 저장과 조회는 Collector의 주 임무가 아니다. 실제 보관과 검색은 Tempo·Mimir·Loki, Jaeger·Prometheus 또는 OTLP를 받는 상용 서비스 같은 Backend가 담당한다.
Grafana Alloy는 공식 설명상 OpenTelemetry Collector 배포판이면서 Prometheus 파이프라인과 Loki·Pyroscope 등 Grafana 생태계 연결 기능을 함께 제공하는 오픈소스 텔레메트리 Collector다. Grafana 제품 이름이 붙었지만 호환되는 다른 Backend로도 보낼 수 있다. 반대로 OTel을 쓴다고 Alloy가 필수인 것도 아니다. upstream Collector나 다른 배포판을 선택할 수 있다.
| 구분 | OpenTelemetry | Grafana Alloy | 관측 Backend |
| 정체 | 규격·API·SDK·프로토콜·Collector 생태계 | OTel Collector 기반의 실행 가능한 배포판 | 저장·검색·시각화 시스템 |
| 주요 역할 | 신호 생성 방식과 데이터 표현·전송을 표준화 | 수신, 변환, 필터, 배치, 라우팅, 내보내기 | 장기 보관, 질의, 대시보드, 경보 |
| 반드시 함께 써야 하나 | Alloy 외 Collector도 선택 가능 | OTel 외 Prometheus·Loki 계열 컴포넌트도 지원 | 요구사항에 따라 교체 가능 |
| 기억할 경계 | OTel은 단일 저장소가 아니다 | Alloy는 분석 화면이나 권한 원장이 아니다 | Backend가 계측 코드를 대신하지 않는다 |
신호 하나가 이동하는 전체 경로
예를 들어 결제 API가 요청 하나를 처리한다고 하자. OTel SDK가 checkout-api라는 Resource와 TraceId가 포함된 Span을 만든다. Exporter는 이를 OTLP/gRPC 또는 OTLP/HTTP로 Alloy에 보낸다. Alloy의 OTLP Receiver가 받고, Memory Limiter가 과도한 메모리 사용을 제어하며, Batch Processor가 여러 레코드를 묶어 전송 횟수를 줄인다. 마지막 Exporter가 선택한 Backend로 전달한다.
애플리케이션 계측
→ OTLP/gRPC 또는 OTLP/HTTP
→ Alloy OTLP Receiver
→ Memory Limiter
→ Batch Processor
→ Exporter
→ Tempo·Mimir·Loki 또는 다른 호환 Backend
여기서 중요한 것은 “세 신호를 한곳에 넣는다”보다 동일한 서비스 이름, 환경, TraceId 같은 상관관계 문맥을 유지한다는 점이다. Collector가 지나간다고 서로 무관한 Log와 Trace가 자동으로 연결되지는 않는다. 계측 단계에서 문맥을 제대로 생성하고 전파해야 한다.
OTLP에는 gRPC와 HTTP 전송 방식이 있다. 일반적으로 gRPC 수신 포트는 4317, HTTP 수신 포트는 4318을 사용한다. 다만 포트가 열려 있다는 사실이 인증과 암호화를 의미하지는 않는다. 네트워크 경계 밖에서 받을 때는 TLS, 인증, 접근제어를 별도로 설계해야 한다.
왜 애플리케이션이 Backend로 직접 보내지 않을까
작은 개발 환경에서는 SDK가 Backend로 직접 내보내도 된다. 공식 OpenTelemetry 문서도 시작 단계의 직접 전송을 가능한 선택지로 설명한다. 하지만 서비스마다 Backend 주소와 인증 방식을 넣으면 변경 범위가 커지고, 재시도·배치·필터 정책도 애플리케이션별로 흩어진다.
Collector 계층을 두면 애플리케이션은 가까운 OTLP Endpoint로 빠르게 신호를 넘기고 본업으로 돌아갈 수 있다. 재시도, 배치, 민감정보 필터링, 여러 목적지로의 분기는 Collector에서 관리한다. 다만 Collector가 새 병목과 장애점이 되므로 큐 적체, 거부·폐기 수, 메모리와 Exporter 실패를 반드시 관측해야 한다.
배치 위치도 중요하다. Grafana 문서는 OTel 컴포넌트를 쓰는 모든 Alloy에 Batch Processor 구성을 강하게 권장하고, Memory Limiter와 샘플링처럼 데이터를 버릴 수 있는 Processor 뒤에 두도록 안내한다. 그래야 최종적으로 남은 데이터를 효율적으로 묶을 수 있다.
실습: Podman에서 Alloy 환승센터 열기
이번 실습은 외부 Backend나 클라우드 자격증명을 사용하지 않는다. OTLP로 들어온 데이터를 Alloy의 Debug Exporter가 컨테이너 로그에 출력하는 폐쇄형 검증이다. 민감한 운영 데이터를 보내지 말고 샘플 신호만 사용한다.
1단계: 작업 디렉터리와 설정 파일 준비
새 디렉터리에서 config.alloy를 만든다.
mkdir -p alloy-lab
cd alloy-lab
logging {
level = "info"
format = "logfmt"
}
otelcol.receiver.otlp "lab" {
grpc {
endpoint = "0.0.0.0:4317"
}
http {
endpoint = "0.0.0.0:4318"
}
output {
metrics = [otelcol.processor.memory_limiter.lab.input]
logs = [otelcol.processor.memory_limiter.lab.input]
traces = [otelcol.processor.memory_limiter.lab.input]
}
}
otelcol.processor.memory_limiter "lab" {
check_interval = "1s"
limit = "256MiB"
output {
metrics = [otelcol.processor.batch.lab.input]
logs = [otelcol.processor.batch.lab.input]
traces = [otelcol.processor.batch.lab.input]
}
}
otelcol.processor.batch "lab" {
timeout = "1s"
send_batch_size = 512
output {
metrics = [otelcol.exporter.debug.lab.input]
logs = [otelcol.exporter.debug.lab.input]
traces = [otelcol.exporter.debug.lab.input]
}
}
otelcol.exporter.debug "lab" {
verbosity = "detailed"
}
이 설정은 Receiver → Memory Limiter → Batch → Debug Exporter라는 방향 그래프다. Alloy 기본 엔진은 YAML이 아니라 Alloy 문법으로 컴포넌트의 output을 다음 컴포넌트의 input에 연결한다. 2026년 9월 현재 upstream Collector YAML을 직접 실행하는 alloy otel 엔진도 있지만 공식 문서상 Experimental이므로, 이 실습에서는 안정적인 기본 엔진을 사용한다.
2단계: 설정을 먼저 검증하기
실행 전에 컨테이너의 validate 명령으로 문법과 컴포넌트 연결을 검사한다. <ALLOY_VERSION>은 공식 릴리스에서 검증한 고정 버전으로 바꾼다. latest는 실습 재현성을 떨어뜨리므로 본문 명령에서는 사용하지 않는다.
podman run --rm \
-v "$PWD/config.alloy:/etc/alloy/config.alloy:Z,ro" \
docker.io/grafana/alloy:v1.19.0 \
validate /etc/alloy/config.alloy
성공하면 설정 오류 없이 종료한다. 실패하면 줄 번호와 컴포넌트 이름을 확인한 뒤 다음 단계로 넘어가지 않는다.
3단계: Alloy 실행하기
podman run --rm -d --name alloy-lab \
-p 127.0.0.1:12345:12345 \
-p 127.0.0.1:4317:4317 \
-p 127.0.0.1:4318:4318 \
-v "$PWD/config.alloy:/etc/alloy/config.alloy:Z,ro" \
docker.io/grafana/alloy:v1.19.0 \
run --server.http.listen-addr=0.0.0.0:12345 \
--storage.path=/var/lib/alloy/data \
/etc/alloy/config.alloy
호스트 바인딩을 127.0.0.1로 제한한 이유는 실습용 무인증 OTLP Receiver와 디버그 UI를 외부에 노출하지 않기 위해서다. 브라우저에서 http://127.0.0.1:12345를 열면 컴포넌트 상태와 연결 그래프를 확인할 수 있다.
4단계: 프롬프트만으로 샘플 앱 계측하기
사용하는 LLM 코딩 도구에 아래 프롬프트를 입력한다. 생성된 코드는 실행 전에 파일 목록과 의존성을 검토하고, 비밀값이나 외부 전송 주소가 없는지 확인한다.
Python으로 최소 HTTP 서버를 만들어 줘. OpenTelemetry 공식 SDK와 OTLP Exporter를 사용하고, 서비스 이름은 alloy-lab-app으로 설정해 줘. /work 요청을 받으면 부모 Span 하나와 자식 Span 하나, Counter Metric 하나, TraceId가 포함된 구조화 Log 하나를 만들고 http://127.0.0.1:4318로 OTLP/HTTP 전송해 줘. 필요한 requirements.txt, 실행 명령, 요청 명령을 함께 작성하되 외부 서비스와 자격증명은 사용하지 마.
생성 결과가 언어별 공식 패키지 이름과 현재 API에 맞는지 확인한 뒤 격리된 가상환경에서 실행한다. /work를 몇 차례 호출하고 다음 명령으로 Alloy 출력을 본다.
podman logs -f alloy-lab
기대 결과는 alloy-lab-app Resource와 생성한 Span·Metric·Log Record가 Debug Exporter 출력에 나타나는 것이다. TraceId를 비교해 요청 하나에서 나온 신호가 연결되는지 확인한다. 디버그 출력은 학습용이며 대량 운영 트래픽에는 적합하지 않다.
5단계: 종료와 정리
실습이 끝나면 다음처럼 종료한다. --rm 옵션 때문에 정지된 컨테이너도 함께 제거된다.
podman stop alloy-lab
Backend로 바꿀 때 달라지는 것
실습의 Debug Exporter를 OTLP Exporter로 바꾸면 Alloy 뒤에 실제 Backend를 연결할 수 있다. OTLP를 지원하는 단일 Endpoint로 세 신호를 보내거나, Log는 Loki, Trace는 Tempo, Metric은 Prometheus 호환 저장소로 서로 다르게 라우팅할 수도 있다.
이때 Endpoint, 프로토콜, 인증 방식은 Backend 문서를 따라야 한다. 예를 들어 HTTP/HTTPS Endpoint에는 otelcol.exporter.otlphttp, gRPC Endpoint에는 otelcol.exporter.otlp가 대응한다. API Token을 설정 파일에 평문으로 적지 말고 환경 변수나 조직의 Secret 관리 체계를 사용한다. 여러 Tenant가 공유하는 환경이라면 수신 인증과 Tenant 식별을 신뢰할 수 있는 Gateway에서 강제하고, 클라이언트가 보낸 Tenant 속성을 그대로 믿지 않는다.
| 배치 방식 | 장점 | 주의할 점 | 어울리는 환경 |
| 애플리케이션에서 Backend로 직접 전송 | 구성 요소가 적고 시작이 빠름 | 인증·재시도·목적지 설정이 서비스별로 분산 | 개인 개발, 짧은 검증 |
| 호스트별 Agent | 애플리케이션과 가까워 빠르게 넘길 수 있음 | 노드 수만큼 배포·업데이트 필요 | VM, Kubernetes DaemonSet |
| 중앙 Gateway | 정책과 Exporter를 한곳에서 관리 | 병목·단일 장애점·Tenant 격리 필요 | 여러 팀이 공유하는 플랫폼 |
| Agent + Gateway | 로컬 수집과 중앙 정책을 분리 | 두 계층의 용량·장애 대응이 필요 | 규모가 큰 운영 환경 |
운영에 넣기 전 보안·신뢰성 체크리스트
- OTLP Receiver와 Alloy 관리 UI를 필요한 인터페이스와 네트워크에만 바인딩한다.
- Collector 간 또는 원격 클라이언트 연결에는 TLS와 인증을 적용한다.
- Log 본문, Span Attribute, Resource Attribute에 Token·세션·개인정보를 넣지 않는다.
- 필터와 마스킹은 Export 직전 한 번만이 아니라 가능한 한 계측 원천부터 적용한다.
- Memory Limiter, Batch, 전송 큐와 재시도를 트래픽 특성에 맞게 조정한다.
- 수신량, 거부·폐기량, 큐 적체, Export 실패, 재시작 횟수와 메모리를 감시한다.
- 서비스명과 환경명 같은 Resource 속성의 조직 표준을 정하고, 고카디널리티 값을 Metric Label로 남발하지 않는다.
- 컨테이너 버전 또는 Digest를 고정하고, 설정은 읽기 전용으로 마운트하며, 최소 권한으로 실행한다.
- Debug Exporter의 상세 출력에는 원문 데이터가 보일 수 있으므로 운영에서 비활성화한다.
- 장애 실험으로 Backend 지연·중단을 만들어 데이터 손실과 애플리케이션 영향 범위를 확인한다.
텔레메트리에는 사용자 식별자, URL, 쿼리, 오류 내용과 내부 네트워크 구조가 섞일 수 있다. OpenTelemetry 공식 보안 문서도 PII 노출, 데이터 변조, 규정 준수와 DoS를 Collector 보안의 주요 이유로 든다. 관측 파이프라인 역시 보호해야 할 데이터 파이프라인이다.
결론: 표준과 운송 프로그램을 분리해 이해하자
OpenTelemetry는 Log·Trace·Metric을 공통 방식으로 만들고 연결하고 전달할 수 있게 하는 표준과 생태계다. Grafana Alloy는 그 신호를 실제로 받아 가공하고 라우팅하는 Collector 배포판이다. OTel은 Backend가 아니고, Alloy는 Grafana 전용 통로가 아니며, Collector를 둔다고 상관관계와 보안이 자동으로 완성되는 것도 아니다.
가장 작은 출발점은 로컬 OTLP Receiver와 Debug Exporter다. 여기서 Resource, TraceId와 세 신호의 도착을 확인한 뒤 Memory Limiter와 Batch를 유지한 채 실제 Backend Exporter로 교체한다. 다음 단계에서는 Tempo·Loki·Prometheus 계열 저장소에 도착한 신호를 Grafana에서 서로 이동하며 조회하는 방법을 살펴볼 수 있다.
공식 참고 자료
- OpenTelemetry 구성 요소
- OpenTelemetry Collector
- OpenTelemetry Collector 컴포넌트
- OpenTelemetry 보안
- Grafana Alloy 소개
- Grafana Alloy의 OpenTelemetry
- Alloy OTLP Receiver
- Alloy Memory Limiter Processor
- Alloy Batch Processor
- Docker 컨테이너로 Alloy 실행
카테고리: 클라우드/opentelemetry
태그: OpenTelemetry, Grafana Alloy, OTLP, Observability, Collector, Log, Trace, Metric
'클라우드 > opentelemetry' 카테고리의 다른 글
| 관측 시스템 조립하기: LLM 보안 관측 스택 (0) | 2026.09.03 |
|---|---|
| 세 가지 보안 신호: Log·Trace·Metric을 연결해야 사고가 보인다 (0) | 2026.09.03 |
| 💥 OpenTelemetry 예외 처리, 이거 모르면 큰일납니다! (성능과 안정성 둘 다 잡는 비법) (0) | 2025.11.11 |
| OpenTelemetry 메트릭, CUMULATIVE vs DELTA 헷갈리면 큰일나는 이유 🚨 (1) | 2025.11.11 |
| 당신의 OpenTelemetry Collector는 왜 느릴까? 😮 Headless Service로 완벽 해결! (0) | 2025.11.11 |