#OTel 운영 플레이북
버전: 0.33.0 최종 업데이트: 2026-03-15 적용 대상: ranvier-inspector 카테고리: 가이드
#1. 목적
이 플레이북은 기술적 OTel 통합 (M149, 검증된 스모크 테스트)과 실제 조직에서의 운영 배포 사이의 격차를 해소합니다. 자격증명 매핑, 정책 적용, 벤더 구성, 환경 전략, 보안 강화, 멀티 테넌트 격리, 문제 해결을 다룹니다.
전제조건:
otel_interop_matrix.md에 설명된 기본 OTel 상호운용성 검증을 완료했어야 합니다. 이 플레이북은 Ranvier 애플리케이션이 이미ranvier-inspector를 통해 span을 생성하고 있다고 가정합니다.
#2. 자격증명 매핑
#2.1 패턴 개요
Service Account → OTLP Auth Header → Collector → BackendRanvier는 OTLP (gRPC 또는 HTTP/protobuf)를 통해 트레이스를 내보냅니다. 인증은 Collector exporter 수준에서 설정되며 — Ranvier 애플리케이션 코드에서가 아닙니다. 이를 통해 비밀 관리가 애플리케이션 배포와 분리됩니다.
#2.2 API 키 / Bearer 토큰 매핑
권장 패턴: 환경 변수 주입
# otel-collector.yaml — exporter 섹션
exporters:
otlp/backend:
endpoint: "https://otlp.backend.example.com:4317"
headers:
Authorization: "${BACKEND_OTLP_TOKEN}" # 런타임에 주입
tls:
insecure: false토큰 주입 방법:
- Kubernetes Secret → Collector 디플로이먼트에 환경 변수로 마운트
- Docker Compose →
env_file:또는secrets:블록 - CI/CD → 배포 시 Collector 컨테이너에 주입
소스 컨트롤에 커밋되는 설정 파일에 토큰을 절대 포함하지 마세요.
#2.3 환경별 계정 분리
| 환경 | 서비스 계정 | 토큰 소스 |
|---|---|---|
dev |
svc-ranvier-dev |
.env.local (커밋하지 않음) |
staging |
svc-ranvier-staging |
CI 시크릿 OTEL_STAGING_TOKEN |
prod |
svc-ranvier-prod |
Vault / KMS / 클라우드 시크릿 매니저 |
#2.4 멀티 백엔드 자격증명 격리
여러 백엔드로 전송하는 경우 (예: 프로덕션에는 Datadog, 스테이징 디버그에는 Jaeger):
exporters:
otlphttp/datadog:
endpoint: "https://trace.agent.datadoghq.com"
headers:
DD-API-KEY: "${DATADOG_API_KEY}"
otlp/jaeger:
endpoint: "jaeger:4317"
tls:
insecure: true자격증명 유출을 방지하기 위해 백엔드별로 별도의 파이프라인을 사용하세요.
#3. 수정(Redaction) 정책 선택
Ranvier의 ranvier-inspector 확장은 OTLP exporter 수준에서 적용되는 세 가지 수정 모드를 지원합니다:
| 모드 | 설명 | 사용 사례 |
|---|---|---|
public |
모든 사용자 식별 가능 필드 제거 | 외부 공개 내보내기 (CDN 로그, 서드파티 SaaS) |
internal |
서비스/트레이스 메타데이터 유지, PII 제거 | 내부 관측 플랫폼 |
strict |
모든 것 유지 (원시 span) | 로컬 개발, Jaeger 스모크 테스트 |
#3.1 모드 선택
Collector에서 환경 변수로 설정합니다:
processors:
attributes/redact_public:
actions:
- key: user.id
action: delete
- key: user.email
action: delete
- key: http.request.header.authorization
action: delete또는 Ranvier의 inspector 확장을 통해 설정합니다:
// ranvier-inspector 설정에서
Inspector::builder()
.redaction_mode(RedactionMode::Public) // 또는 Internal, Strict#3.2 프로덕션에서의 적용
심층 방어를 위해 두 경계에서 수정을 적용합니다:
- 애플리케이션 수준 (
ranvier-inspector): span 생성 시 제거 - Collector 수준 (attribute 프로세서): 내보내기 전 최종 게이트
이를 통해 애플리케이션 수준 필터가 잘못 구성된 경우에도 우발적 유출을 방지합니다.
#3.3 검증된 수정 경로
Ranvier → OTel Collector (redaction processor) → OTLP exporter근거: docs/03_guides/otel_collector_otlp_redaction_smoke.md
#4. 환경 기반 구성
#4.1 구성 전략
dev → stdout/console exporter (네트워크 의존성 없음)
staging → OTel Collector → Jaeger (로컬 Docker)
prod → OTel Collector → Backend SaaS (Datadog / New Relic)#4.2 Dev (로컬 콘솔)
# config/otel.dev.toml
[otel]
exporter = "console"
sampler = "always_on"
service_name = "${SERVICE_NAME:-my-service}-dev"Collector가 필요 없습니다. 개발 중에 span이 stdout에 표시됩니다.
#4.3 Staging (Docker Compose를 통한 Jaeger)
# docker-compose.staging.yml
services:
jaeger:
image: jaegertracing/all-in-one:1.55
ports:
- "16686:16686" # UI
- "4317:4317" # OTLP gRPC
otel-collector:
image: otel/opentelemetry-collector-contrib:0.96.0
volumes:
- ./docs/03_guides/otel_collector_jaeger_config.yaml:/etc/otelcol/config.yaml
depends_on: [jaeger]참조 구성: docs/03_guides/otel_collector_jaeger_config.yaml
#4.4 프로덕션 (SaaS 백엔드)
docs/03_guides/otel_vendor_configs/에 있는 벤더별 구성을 사용합니다.
프로덕션 주요 원칙:
- 항상 TLS 사용 (
insecure: false) - 복원력을 위해
retry_on_failure와sending_queue설정 - 적절한 비율로
sampler = "parentbased_traceidratio"사용 (예: 높은 트래픽 서비스에서 0.1)
# 권장 프로덕션 샘플러
sampler:
type: parentbased_traceidratio
argument: "0.1" # 루트 span의 10% 샘플링#5. 벤더별 빠른 참조
| 벤더 | 엔드포인트 | 인증 | 설정 파일 |
|---|---|---|---|
| Datadog | https://trace.agent.datadoghq.com |
DD-API-KEY 헤더 |
otel_collector_datadog_class_backend_config.yaml |
| New Relic | https://otlp.nr-data.net:4317 |
api-key 헤더 |
otel_vendor_configs/new_relic.yaml |
| Honeycomb | https://api.honeycomb.io:443 |
x-honeycomb-team 헤더 |
otel_vendor_configs/honeycomb.yaml |
| Jaeger | jaeger:4317 (gRPC, 로컬) |
없음 (내부) | otel_collector_jaeger_config.yaml |
| Tempo | tempo:4317 (gRPC, 로컬) |
없음 (내부) | otel_collector_tempo_config.yaml |
빠른 시작 안내는 docs/03_guides/otel_vendor_configs/README.md를 참조하세요.
#6. 보안 강화
#6.1 토큰 로테이션
- 백엔드 API 키를 일정에 따라 로테이션 (30–90일)
- 지원되는 경우 단기 토큰 사용 (OIDC 워크로드 아이덴티티)
- Vault / AWS Secrets Manager / GCP Secret Manager에 시크릿 저장
- OTLP 인증 헤더를 절대 로깅하지 않음 — Collector 로그 수준을
warn으로 설정
#6.2 TLS 구성
모든 프로덕션 OTLP 연결은 TLS를 사용해야 합니다:
exporters:
otlp/backend:
tls:
insecure: false
ca_file: /etc/ssl/certs/ca-certificates.crt # 또는 벤더 CA 번들자체 호스팅 백엔드 (Jaeger/Tempo)의 스테이징 환경에서는 mTLS를 권장합니다:
tls:
cert_file: /certs/client.crt
key_file: /certs/client.key
ca_file: /certs/ca.crt#6.3 네트워크 정책 (Kubernetes)
애플리케이션 파드에서 Collector로만 송신을 제한합니다:
# NetworkPolicy: app → collector만 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-otel-collector
spec:
podSelector:
matchLabels:
app: ranvier-service
egress:
- to:
- podSelector:
matchLabels:
app: otel-collector
ports:
- protocol: TCP
port: 4317#7. 멀티 테넌트 관측 격리
여러 테넌트가 동일한 Ranvier 배포를 사용하는 경우:
#7.1 속성 기반 격리
모든 span에 tenant.id 속성을 태그합니다:
// Ranvier transition에서
#[transition]
async fn handle(_: (), _: &(), bus: &mut Bus) -> Outcome<String, Error> {
let tenant = bus.read::<TenantContext>().map(|t| t.id.clone()).unwrap_or_default();
tracing::Span::current().set_attribute("tenant.id", tenant);
Outcome::Next("ok".to_string())
}#7.2 Collector 수준 라우팅
tenant.id를 기반으로 span을 다른 백엔드로 라우팅합니다:
processors:
filter/tenant_a:
spans:
include:
match_type: strict
attributes:
- key: tenant.id
value: "tenant-a"
exporters:
otlp/tenant_a:
endpoint: "https://tenant-a.observability.example.com:4317"
headers:
Authorization: "${TENANT_A_TOKEN}"#7.3 데이터셋 격리 (Honeycomb / New Relic)
Honeycomb과 New Relic 모두 API 키를 통해 기본적으로 데이터셋/팀 수준 격리를 지원합니다. 테넌트별 API 키를 사용하고 위의 Collector 라우팅 패턴으로 주입합니다.
#8. 문제 해결 런북
#8.1 Span이 표시되지 않음
| 증상 | 예상 원인 | 조치 |
|---|---|---|
| Jaeger UI에 출력 없음 | Collector 미실행 | docker ps / podman ps — Collector 시작 |
| Collector 실행 중이나 span 없음 | OTLP 엔드포인트 잘못 설정 | OTEL_EXPORTER_OTLP_ENDPOINT 환경 변수 확인 |
| Collector 로그에 span 표시되나 백엔드에 없음 | 백엔드 인증 실패 | API 키 확인, curl로 테스트 |
| 샘플러가 모든 span 드롭 | traceidratio가 너무 낮음 |
디버깅을 위해 1.0으로 설정 |
# 빠른 연결 테스트 (gRPC)
grpcurl -plaintext localhost:4317 list
# 빠른 연결 테스트 (HTTP/protobuf)
curl -I http://localhost:4318/v1/traces#8.2 수정(Redaction)이 작동하지 않음
ranvier-inspector버전≥ 0.26.0확인- 애플리케이션 수준과 Collector 수준 수정이 모두 구성되어 있는지 확인
- Collector 디버그 로그를 일시적으로 활성화:
service.telemetry.logs.level: debug
#8.3 높은 카디널리티 / 샘플링
높은 트래픽 서비스 (>1000 RPS)의 경우 부모 기반 비율 샘플링을 사용합니다:
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.05 # 5%#8.4 Collector의 메모리 / CPU 급증
memory_limiter프로세서 활성화 (항상 파이프라인의 첫 번째)batch프로세서에send_batch_size: 1024와timeout: 10s사용- 로드 밸런서 뒤에서 Collector를 수평 확장
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 20
batch:
send_batch_size: 1024
timeout: 10s#8.5 시계 스큐 / Span 순서 문제
Jaeger/Tempo에서 span이 순서가 맞지 않게 표시되는 경우:
- 모든 서비스가 NTP 동기화를 사용하는지 확인
OTEL_SDK_DISABLED=false를 설정하고 컨테이너의 시계 소스를 확인
#9. 참조 링크
| 문서 | 목적 |
|---|---|
| `otel_interop_matrix.md` | 검증된 상호운용성 경로 (M149) |
| `otel_collector_smoke_baseline.md` | 디버그 exporter 스모크 테스트 |
| `otel_collector_jaeger_smoke.md` | Jaeger 스모크 테스트 |
| `otel_collector_tempo_smoke.md` | Tempo 스모크 테스트 |
| `otel_collector_datadog_class_smoke.md` | Datadog 클래스 릴레이 스모크 테스트 |
| `otel_collector_otlp_redaction_smoke.md` | 수정 어댑터 스모크 테스트 |
| `otel_vendor_configs/README.md` | 벤더 설정 카탈로그 |
ranvier/examples/otel-ops-demo/ |
정책 적용 데모 |