본문 바로가기
IT/k8s

[k8s] OpenTelemetry K8s 마이그레이션: Prometheus 공존 전략과 함정

by 수누다 2026. 7. 2.

OpenTelemetry K8s 마이그레이션: Prometheus 공존 전략과 함정

요즘 Prometheus에서 OpenTelemetry K8s로 마이그레이션을 고민하는 분들이 정말 많아요. 저도 홈랩이랑 사내 Kubernetes(쿠버네티스, 컨테이너 오케스트레이션) 환경을 굴리면서 비슷한 고민을 꽤 오래 했거든요. 기존 Prometheus(프로메테우스, 메트릭 수집 시스템)는 익숙하고 강력한데, 로그와 트레이스(trace, 분산 추적)까지 한 방향으로 정리하려고 보면 슬슬 한계가 보이더라고요. 특히 K8s 모니터링이 메트릭 중심으로만 굳어져 있으면 장애 원인 추적이 길어지고, 팀마다 도구가 갈라지는 순간 운영 피로도가 확 올라갑니다.

처음엔 저도 "Prometheus 잘 쓰고 있는데 굳이 바꿔야 하나?" 싶었어요. 근데 실제로 OpenTelemetry(오픈텔레메트리, 통합 관측성 표준)를 붙여보니, 이건 단순히 수집기 하나 바꾸는 작업이 아니더군요. 옵저버빌리티 전환의 기준을 다시 세우는 일에 가깝습니다. 그래서 이번 글에서는 OpenTelemetry K8s 마이그레이션을 할 때 어떤 순서로 접근해야 덜 망가지는지, 어디서 많이 삽질하는지, 그리고 Prometheus를 완전히 버리기보다 어떻게 현실적으로 공존시킬지 제 경험 기준으로 풀어볼게요.

Prometheus 중심 구조에서 OpenTelemetry Collector 중심 구조로 전환되는 전체 흐름을 한눈에 보여주는 이미지입니다.

왜 지금 OpenTelemetry K8s 마이그레이션 이야기가 많을까

쉽게 말해, 예전에는 메트릭(metrics, 수치형 운영 데이터)만 잘 봐도 운영이 됐어요. CPU, 메모리, 요청 수, 에러율 정도만 봐도 웬만한 장애는 잡혔거든요. 그런데 마이크로서비스가 늘어나고, 서비스 간 호출이 복잡해지면 그걸로는 부족합니다. 에러율이 올라간 건 알겠는데 어디서부터 꼬였는지를 찾는 시간이 너무 오래 걸려요.

OpenTelemetry는 바로 이 지점을 건드립니다. 메트릭, 로그(logs, 로그 데이터), 트레이스까지 한 모델로 가져가려고 하죠. 여기서 중요한 포인트가 하나 있습니다. OpenTelemetry는 Prometheus의 완전한 대체재라기보다, 수집과 전송의 표준화 계층으로 이해하는 게 맞습니다. 저도 처음엔 이걸 헷갈려서 설계를 잘못 잡았었는데, Prometheus가 잘하던 영역과 OpenTelemetry가 잘하는 영역이 미묘하게 달라요.

  • Prometheus: pull 기반 메트릭 수집, PromQL(프로메스큐엘, Prometheus 질의 언어), 알림 규칙에 강합니다.
  • OpenTelemetry: 메트릭, 로그, 트레이스의 표준화된 수집과 변환, 다양한 백엔드 전송에 강해요.
  • Collector: 수집기이자 중간 파이프라인입니다. 여기서 필터링, 배치, 리소스 태깅을 처리하죠.

그래서 Prometheus에서 OpenTelemetry K8s로 마이그레이션은 보통 "Prometheus 삭제"가 아니라, "수집 구조를 Collector 중심으로 재편하고 필요한 부분만 점진 전환"으로 가야 안전합니다.

개념 먼저 정리: Prometheus와 OpenTelemetry는 어떻게 다른가

저도 처음엔 용어가 너무 많아서 헷갈렸어요. Operator(오퍼레이터, 쿠버네티스 앱 관리 자동화), Exporter(익스포터, 특정 시스템 메트릭 노출기), Receiver(리시버, 수집 입력), Processor(프로세서, 데이터 가공기), Exporter는 또 OpenTelemetry 안에서도 다른 뜻으로 쓰이거든요. 여기서 한 번 깔끔하게 정리해볼게요.

항목 Prometheus 중심 구조 OpenTelemetry 중심 구조
수집 방식 주로 pull pull + push 혼합 가능
주요 대상 메트릭 메트릭, 로그, 트레이스
표준화 도구 중심 벤더 중립 표준
가공 처리 제한적 Collector에서 풍부하게 처리
전환 난이도 익숙함 설계 이해가 필요해요

쉽게 말해 이런 느낌입니다.

  1. Prometheus는 메트릭 수집과 조회에 특화된 도구예요.
  2. OpenTelemetry는 데이터를 어떻게 모으고, 어떤 속성(attribute, 속성값)을 붙이고, 어디로 보낼지 표준화합니다.
  3. Kubernetes 환경에서는 OpenTelemetry Collector가 사실상 핵심이죠.

여기서 독자분들이 가장 많이 오해하는 부분이 있어요. OpenTelemetry를 도입한다고 해서 PromQL 기반 대시보드나 알림을 바로 버릴 필요는 없습니다. 저도 이 부분을 무리하게 한 번에 바꾸려다가 롤백했었어요. 기존 운영 체계를 존중하면서 단계별로 옮겨야 합니다.

마이그레이션 전에 먼저 결정해야 할 4가지

실제로 써보니까, 기술보다 먼저 정해야 하는 건 운영 기준이었어요. 이걸 안 정하면 설정은 돌아가도 팀이 힘들어집니다.

1. 최종 백엔드가 무엇인지 정하기

Collector는 중간 계층이죠. 결국 메트릭과 트레이스를 어디에 저장하고 조회할지 정해야 해요. 기존 Prometheus를 유지할지, OTLP(OTLP, OpenTelemetry Protocol) 수신 가능한 백엔드를 붙일지, 로그 저장소와 어떻게 나눌지 먼저 결정해야 합니다.

2. 어떤 신호(signal)부터 옮길지 정하기

메트릭부터 갈지, 애플리케이션 트레이스부터 붙일지, 노드/파드 수준 K8s 모니터링부터 정리할지 우선순위를 잡아야 해요. 제 경험상 가장 무난한 순서는 이렇습니다.

  1. 인프라 메트릭 유지
  2. Collector 배포
  3. 애플리케이션 트레이스 추가
  4. 메트릭 라우팅 정리
  5. 로그 연계 검토

3. 라벨(label)과 리소스 속성(attribute) 기준 통일

이게 진짜 중요합니다. Prometheus 쪽 label과 OpenTelemetry 쪽 resource attribute가 섞이면 쿼리와 대시보드가 다 꼬여요. namespace, pod, service, cluster 같은 공통 키를 먼저 합의하세요.

4. 샘플링(sampling, 일부만 수집) 전략 정하기

트레이스는 전부 모으면 부담이 커져요. 특히 K8s에서 서비스 수가 많아지면 수집량이 금방 늘어요. 처음부터 100% 수집을 고집하기보다, 핵심 서비스 기준으로 시작하는 게 현실적입니다.

OpenTelemetry K8s 마이그레이션에서 Collector 구성도

DaemonSet 또는 Deployment 형태의 Collector가 어떤 데이터를 받고 어디로 보내는지 설명하는 구성 이미지입니다.

실전 구현: Kubernetes에 OpenTelemetry Collector 배포하기

이제 실제 구성을 봐볼게요. 여기서는 가장 많이 쓰는 패턴인 Collector를 Kubernetes에 배포하고, Prometheus scrape 대상 일부를 Collector로 옮기는 방식을 기준으로 설명하겠습니다. 특정 배포 도구를 강제하진 않을게요. Helm(헬름, 쿠버네티스 패키지 매니저)을 쓰든 매니페스트를 쓰든 핵심 구조는 비슷하거든요.

1. 기본 Collector 설정 예시

아래 예시는 개념 설명용으로 단순화한 구성입니다. 실제 운영에서는 인증, 리소스 제한, 백엔드 주소, 필터링 규칙을 환경에 맞춰 넣어야 해요.

receivers:
  otlp:
    protocols:
      grpc:
      http:
  prometheus:
    config:
      scrape_configs:
        - job_name: 'kubernetes-pods'
          kubernetes_sd_configs:
            - role: pod
          relabel_configs:
            - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
              action: keep
              regex: true

processors:
  batch:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 75
    spike_limit_percentage: 15
  resource:
    attributes:
      - key: deployment.environment
        value: homelab
        action: upsert

exporters:
  debug: {}
  otlp:
    endpoint: otel-backend.example.local:4317
    tls:
      insecure: true

service:
  pipelines:
    metrics:
      receivers: [prometheus, otlp]
      processors: [memory_limiter, batch, resource]
      exporters: [debug, otlp]
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, resource]
      exporters: [debug, otlp]

여기서 핵심은 세 가지예요.

  • receivers: 데이터를 어디서 받을지 정의합니다.
  • processors: 배치 처리, 메모리 제한, 공통 속성 추가를 담당해요.
  • exporters: 어디로 보낼지 정의합니다.

처음엔 debug exporter를 꼭 켜두세요. 저도 이걸 안 켜고 한참 헤맸어요. 데이터가 안 보일 때 수집이 안 되는 건지, 가공이 잘못된 건지, 전송이 막힌 건지 구분이 안 되거든요.

2. Kubernetes 리소스 예시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-collector
  namespace: observability
spec:
  replicas: 2
  selector:
    matchLabels:
      app: otel-collector
  template:
    metadata:
      labels:
        app: otel-collector
    spec:
      containers:
        - name: otel-collector
          image: otel/opentelemetry-collector:latest
          args:
            - "--config=/conf/otel-collector-config.yaml"
          ports:
            - containerPort: 4317
            - containerPort: 4318
          volumeMounts:
            - name: config
              mountPath: /conf
      volumes:
        - name: config
          configMap:
            name: otel-collector-config

실무에서는 DaemonSet(데몬셋, 노드마다 하나씩 배포)도 많이 써요. 노드 단위 수집이나 에이전트 성격이 강하면 DaemonSet이 자연스럽고, 중앙 수집기면 Deployment가 편합니다. 둘 중 뭐가 정답이다, 이건 없어요. 수집 대상과 트래픽 경로를 보고 정해야 합니다.

3. 애플리케이션에서 OTLP로 보내기

애플리케이션이 OpenTelemetry SDK를 지원한다면 OTLP endpoint를 Collector로 맞추면 돼요. 언어별 설정은 다르지만 원리는 비슷합니다.

export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc.cluster.local:4318
export OTEL_SERVICE_NAME=my-api
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod,k8s.namespace.name=default

여기서 중요한 포인트! 애플리케이션마다 서비스 이름 규칙이 제각각이면 나중에 대시보드가 정말 난장판이 돼요. 저도 처음엔 서비스명이 코드 저장소 이름, 배포명, 제품명으로 다 달라서 정리하느라 고생했네요 ㅎㅎ

Prometheus를 바로 걷어내지 말고 공존 기간을 두세요

이건 경험에서 나온 조언이에요. 옵저버빌리티 전환을 할 때 가장 위험한 패턴이 "이번 분기 안에 다 바꾸자"예요. 겉보기엔 속도가 나는데, 운영팀만 죽어납니다. 알람 공백이 생기고, 대시보드 신뢰도가 떨어지고, 결국 새 체계가 욕을 먹게 돼요.

제가 추천하는 건 다음과 같은 병행 운영이에요.

  1. 기존 Prometheus 알림과 대시보드는 유지합니다.
  2. OpenTelemetry Collector로 동일한 메트릭 일부를 병행 수집해요.
  3. 핵심 서비스에만 트레이스를 먼저 붙입니다.
  4. 장애 대응 시 새 데이터가 실제로 도움이 되는지 검증해요.
  5. 검증이 끝난 뒤에만 대시보드와 알림을 전환합니다.

이 방식이 느려 보이지만, 실제로는 제일 빨아요. 왜냐면 롤백 비용이 낮거든요.

⚠️ 실제로 많이 겪는 함정과 트러블슈팅

여기부터는 제가 직접 해보니 자주 부딪히는 문제들이에요. OpenTelemetry K8s 마이그레이션에서 대부분 여기서 시간 써요.

1. 라벨과 속성 이름이 서로 달라서 쿼리가 깨짐

Prometheus의 `job`, `instance`, `namespace`와 OpenTelemetry resource attribute가 1:1로 안 맞는 경우가 많아요. 그 결과 대시보드가 비어 보이거나, 같은 서비스가 여러 이름으로 나뉘어 보이죠.

해결: 공통 키 매핑 표를 먼저 만드세요. 운영팀, 개발팀이 같이 보는 문서가 있어야 해요.

2. Collector가 만능인 줄 알고 모든 변환을 몰아넣음

처음엔 저도 그랬어요. 필터링, 이름 변경, 태깅, 라우팅, 샘플링을 Collector 하나에 계속 추가하다 보면 설정이 금방 복잡해져요. 그러면 장애 시 디버깅이 힘들어요.

해결: Processor는 최소한으로 시작하고, 꼭 필요한 것만 추가하세요. 먼저 배치, 메모리 제한, 공통 속성 정도로 출발하는 게 좋아요.

3. 트레이스 수집량 폭증

마이크로서비스 호출이 많으면 생각보다 데이터가 빠르게 늘어나요. 특히 개발 환경에서 무심코 다 켜두면 저장소와 네트워크 부담이 커질 수 있어요.

해결: 전면 수집보다 핵심 API부터 시작하세요. 에러 구간 위주로 샘플링하거나, 특정 네임스페이스부터 적용하는 식이 현실적입니다.

4. Prometheus scrape와 OTLP push를 동시에 붙였는데 중복 메트릭 발생

이거 꽤 흔해요. 같은 애플리케이션 메트릭이 Prometheus scrape 경로와 OTLP 경로 둘 다 들어와서 그래프가 이상해질 수 있어요.

해결: 신호별 소유권을 정하세요. 예를 들어 애플리케이션 메트릭은 OTLP, 인프라 메트릭은 기존 scrape처럼 명확히 나누는 거예요.

5. Kubernetes 메타데이터가 기대만큼 안 붙음

pod, node, namespace 정보가 자동으로 다 붙을 거라 기대했는데, 실제로는 배포 방식이나 권한 설정에 따라 부족할 수 있어요.

해결: 서비스 계정 권한, 리소스 탐지 방식, Collector 배치 위치를 같이 점검하세요. 특히 K8s 메타데이터 enrich(강화)가 안 되면 트러블슈팅 난이도가 확 올라가요.

OpenTelemetry K8s 마이그레이션 함정과 트러블슈팅 이미지

실제 마이그레이션에서 자주 발생하는 문제 지점을 강조한 트러블슈팅 시각 자료입니다.

검증은 이렇게 하시면 돼요

구성이 적용됐다고 끝이 아니에요. 드디어 됐다! 싶었는데 실제로는 일부 서비스만 보이고, 속성 누락이 있고, 중복 수집이 있는 경우가 많거든요. 저는 아래 순서로 검증해요.

  1. Collector 로그에서 수신과 전송 여부를 확인합니다.
  2. 기존 Prometheus 수치와 새 파이프라인 수치를 큰 흐름 기준으로 비교해요.
  3. 트레이스 한 건을 선택해서 서비스 간 호출 연결이 보이는지 확인합니다.
  4. namespace, pod, service 이름이 일관되게 붙는지 확인해요.
  5. 장애 상황을 일부러 만들어서 실제 분석 시간이 줄어드는지 봅니다.

간단한 확인 명령 예시는 이런 식이에요.

kubectl get pods -n observability
kubectl logs -n observability deploy/otel-collector
kubectl port-forward -n observability deploy/otel-collector 4318:4318

그리고 Prometheus 메트릭을 계속 보는 환경이라면, 병행 구간에서는 아래 체크리스트가 유용해요.

  • 기존 알림 규칙이 그대로 동작하는가
  • OpenTelemetry 경로로 들어온 메트릭의 이름과 단위가 일관적인가
  • 트레이스에서 서비스 호출 병목 구간이 눈에 띄는가
  • 운영자가 새 쿼리 모델을 이해할 수 있는가

이 검증을 해보면 단순히 "데이터가 들어온다"보다 중요한 게 보여요. 문제를 더 빨리 찾을 수 있느냐가 진짜 기준이거든요.

OpenTelemetry K8s 마이그레이션 결과 대시보드 이미지

메트릭 그래프와 분산 추적 결과가 함께 보이는 검증 단계의 대시보드 이미지를 배치할 위치입니다.

결과적으로 무엇이 좋아졌나

제가 느낀 가장 큰 변화는 장애 대응 대화가 바뀌었다는 점이에요. 예전에는 "CPU는 정상인데 왜 느리지?"에서 한참 머물렀다면, OpenTelemetry 도입 뒤에는 "어느 서비스 호출에서 지연이 시작됐는지"를 더 빨리 볼 수 있었어요. 이거 진짜 편하더라고요.

물론 Prometheus 자체의 가치가 줄어든 건 아니에요. 여전히 K8s 모니터링에서 메트릭은 기본 중의 기본이고, 알림과 시계열 분석은 아주 중요합니다. 다만 옵저버빌리티 전환 관점에서는 메트릭 중심 운영에서 컨텍스트 중심 운영으로 넘어가는 느낌이 분명히 있어요.

비교 항목 전환 전 전환 후
장애 감지 메트릭 경보 중심 메트릭 + 트레이스 조합
원인 추적 로그를 따로 뒤짐 서비스 호출 흐름 기준 탐색
운영 표준 도구별 설정 분산 Collector 중심 파이프라인 정리
확장성 메트릭 중심 다양한 신호 통합 가능

정리: 성공 전략은 "점진 전환"입니다

이번 글의 핵심을 한 줄로 줄이면 이거예요. Prometheus에서 OpenTelemetry K8s로 마이그레이션할 때는 도구 교체가 아니라 운영 모델 전환으로 접근해야 해요. 저도 처음엔 설정 파일만 맞추면 끝날 줄 알았는데, 실제로는 라벨 체계, 샘플링 기준, 공존 기간 설계가 훨씬 중요했어요.

정리해보면 성공 전략은 이래요.

  • Prometheus를 바로 버리지 말고 공존 기간을 둬요.
  • 메트릭보다 먼저 데이터 모델과 속성 체계를 정리합니다.
  • Collector는 단순하게 시작하고 점진적으로 확장해요.
  • 트레이스는 핵심 서비스부터 붙입니다.
  • 검증 기준은 "수집 여부"가 아니라 "문제 해결 속도"로 잡으세요.

혹시 지금 OpenTelemetry 도입을 검토 중인데 너무 복잡해 보여서 멈춰 계셨다면, 저라면 제일 먼저 Collector 하나 띄우고, 가장 중요한 서비스 한 개에만 트레이스 붙여보는 것부터 권할게요. 그 한 번이 전체 방향을 많이 보여주거든요.

다음 글에서는 Kubernetes 환경에서 OpenTelemetry Collector를 DaemonSet과 Deployment 중 어떤 패턴으로 나누는 게 좋은지, 그리고 운영 중 설정이 비대해질 때 어떻게 분리하는지 다뤄볼 거예요. 이전 글에서 다룬 Prometheus 알림 설계 원칙과 같이 보시면 훨씬 연결이 잘 될 거라고 생각해요.

Prometheus와 OpenTelemetry 점진 전환 전략 요약 이미지

마이그레이션 단계, 주의사항, 검증 포인트를 한 장으로 정리한 요약 이미지가 들어갈 위치입니다.

자주 묻는 질문

Q1. OpenTelemetry를 도입하면 Prometheus는 없어도 되나요?

반드시 그렇진 않아요. 특히 기존 PromQL 쿼리, 대시보드, 알림 체계가 잘 돌아간다면 당분간 공존하는 편이 안전합니다.

Q2. K8s 모니터링은 메트릭부터 옮겨야 하나요?

상황에 따라 다르지만, 보통은 인프라 메트릭은 유지하고 애플리케이션 트레이스부터 붙여보는 방식이 체감 효과가 커요.

Q3. 가장 큰 함정은 무엇인가요?

제가 보기엔 라벨과 속성 체계를 통일하지 않고 시작하는 거예요. 나중에 대시보드와 검색 조건이 전부 어긋나거든요.

Q4. 옵저버빌리티 전환의 성공 기준은 뭔가요?

새 도구가 예뻐 보이는지가 아니라, 장애가 났을 때 원인 찾는 시간이 줄었는지가 핵심이에요. 결국 운영은 그걸로 평가받거든요.