Kubernetes에서 OpenTelemetry와 Fluent Bit를 활용한 관찰성 아키텍처 설계

발행: (2026년 1월 14일 오전 03:00 GMT+9)
7 min read

Source: DZone DevOps

위에 제공된 링크에 포함된 전체 텍스트를 번역하려면 해당 내용을 복사해서 여기 붙여 주세요.
코드 블록, URL 및 기술 용어는 그대로 유지하고, 일반 문장은 한국어로 번역해 드리겠습니다.

왜 OpenTelemetry (OTel)와 Fluent Bit인가?

  • OpenTelemetry는 벤더에 종속되지 않는 CNCF‑주도 프레임워크로, 메트릭, 로그, 트레이스를 표준화된 방식으로 수집합니다. 애플리케이션에 직접 삽입하거나 사이드카/데몬셋으로 실행할 수 있는 SDK, API, 에이전트를 제공합니다.
  • Fluent Bit은 가볍고 고성능인 로그 프로세서이자 포워더입니다. 컨테이너에서 로그를 수집하고 Kubernetes 메타데이터로 풍부하게 만들며, Elasticsearch, Loki, CloudWatch 등 다양한 백엔드로 전달할 수 있습니다.

OTel과 Fluent Bit을 결합하면 통합 파이프라인을 구축할 수 있습니다:

  • OTel Collector는 클러스터에서 메트릭과 트레이스를 수집하고, 프로세서(예: 배치, 속성 풍부화)를 적용한 뒤 관측 플랫폼으로 내보냅니다.
  • Fluent Bit은 로그 수집, 파싱, 라우팅을 담당하며, trace_id, span_id와 같은 공유 식별자를 통해 해당 메트릭 및 트레이스와 로그를 연관시킵니다.

Architecture Overview

flowchart TD
    subgraph K8s Cluster
        A[Application Pods] -->|OTel SDK| B[OTel Collector (DaemonSet)]
        A -->|Fluent Bit Sidecar| C[Fluent Bit (DaemonSet)]
    end
    B -->|Metrics & Traces| D[Observability Backend]
    C -->|Logs| D
    D -->|Correlation UI| E[Dashboard / APM]
  1. Instrumentation – 서비스에 OTel SDK를 추가합니다 (Go, Java, Python, .NET 등 사용 가능).
  2. Collector Deployment – OTel Collector를 DaemonSet으로 배포하고 다음과 같은 구성을 합니다:
    • Prometheus 스크랩을 통해 메트릭을 수신합니다.
    • gRPC/HTTP를 통한 OTLP로 트레이스를 수신합니다.
    • 선택한 백엔드(예: Jaeger, Prometheus, Grafana Cloud)로 데이터를 내보냅니다.
  3. Fluent Bit Deployment – Fluent Bit을 DaemonSet으로 배포하고 다음을 수행합니다:
    • /var/log/containers/*.log에서 컨테이너 로그를 읽습니다.
    • 파드, 네임스페이스, 노드 메타데이터로 로그를 풍부하게 합니다.
    • 로그‑트레이스 상관관계를 가능하게 하기 위해 OTel 트레이스 컨텍스트(있는 경우)를 추가합니다.
    • 로그를 동일한 백엔드 또는 전용 로그 저장소로 전송합니다.

단계별 구현

1. OpenTelemetry SDK 추가

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/trace"
)

func main() {
    // Initialize tracer provider
    tp := otel.GetTracerProvider()
    tracer := tp.Tracer("my-service")
    // Use tracer in your handlers...
}

언어별 스니펫을 스택에 맞는 적절한 SDK로 교체하십시오.

2. OTel Collector 배포

otel-collector-config.yaml 파일 생성:

apiVersion: v1
kind: ConfigMap
metadata:
  name: otel-collector-config
  namespace: observability
data:
  otel-collector-config.yaml: |
    receivers:
      otlp:
        protocols:
          grpc:
          http:
      prometheus:
        config:
          scrape_configs:
            - job_name: 'kubernetes-pods'
              kubernetes_sd_configs:
                - role: pod
    processors:
      batch:
      memory_limiter:
        limit_mib: 400
        spike_limit_mib: 100
        check_interval: 5s
    exporters:
      otlphttp:
        endpoint: "https://api.myobservability.com/v1/traces"
      prometheusremotewrite:
        endpoint: "https://api.myobservability.com/v1/metrics"
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlphttp]
        metrics:
          receivers: [prometheus]
          processors: [batch, memory_limiter]
          exporters: [prometheusremotewrite]

DaemonSet 적용:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: otel-collector
  namespace: observability
spec:
  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"]
          volumeMounts:
            - name: config
              mountPath: /conf
      volumes:
        - name: config
          configMap:
            name: otel-collector-config

3. Fluent Bit 배포

fluent-bit-config.yaml 파일 생성:

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-config
  namespace: observability
data:
  fluent-bit.conf: |
    [SERVICE]
        Flush        5
        Daemon       Off
        Log_Level    info

    [INPUT]
        Name              tail
        Path              /var/log/containers/*.log
        Parser            docker
        Tag               kube.*

    [FILTER]
        Name              kubernetes
        Match             kube.*
        Merge_Log         On
        Keep_Log          Off
        K8S-Logging.Parser On
        K8S-Logging.Exclude On

    [FILTER]
        Name              record_modifier
        Match             *
        Record            trace_id ${TRACE_ID}
        Record            span_id ${SPAN_ID}

    [OUTPUT]
        Name  es
        Match *
        Host  elasticsearch.logging.svc
        Port  9200
        Index kubernetes-logs
        Type  _doc

DaemonSet 적용:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluent-bit
  namespace: observability
spec:
  selector:
    matchLabels:
      app: fluent-bit
  template:
    metadata:
      labels:
        app: fluent-bit
    spec:
      containers:
        - name: fluent-bit
          image: fluent/fluent-bit:latest
          volumeMounts:
            - name: config
              mountPath: /fluent-bit/etc
      volumes:
        - name: config
          configMap:
            name: fluent-bit-config

로그, 메트릭, 트레이스 연관시키기

  • Trace Context Propagation – 서비스가 traceparenttracestate 헤더(W3C Trace Context)를 전파하도록 하세요. Fluent Bit는 로그에서 이러한 헤더를 추출(존재하는 경우)하고 trace_idspan_id 필드로 추가합니다.
  • Unified Dashboards – Grafana나 APM UI에서 트레이스 ID를 클릭하면 관련 로그와 메트릭 그래프를 확인할 수 있어, 엔드‑투‑엔드 가시성을 제공합니다.

이 접근 방식의 장점

이점설명
벤더 독립적계측을 변경하지 않고 백엔드를 전환할 수 있습니다.
확장 가능DaemonSet은 모든 노드에서 실행되어 고처리량 워크로드를 처리합니다.
낮은 오버헤드Fluent Bit의 경량 설계는 CPU/메모리 영향을 최소화합니다.
풍부한 컨텍스트연관된 로그, 메트릭 및 트레이스가 근본 원인 분석을 간소화합니다.

최종 생각

OpenTelemetry와 Fluent Bit을 사용해 쿠버네티스에서 관측성을 설계하면 단일하고 일관된 파이프라인을 모든 텔레메트리 데이터에 제공할 수 있습니다. 수집, 풍부화, 내보내기를 표준화함으로써 운영 복잡성을 줄이고, 사고 대응을 가속화하며, 향후 확장 및 규정 준수 요구에 대한 견고한 기반을 마련합니다.

몇몇 핵심 서비스에 먼저 계측을 적용하고, 콜렉터와 Fluent Bit을 배포한 뒤, 점진적으로 적용 범위를 확대하세요. 그 보상—클라우드 네이티브 애플리케이션에 대한 명확하고 실행 가능한 인사이트—은 노력에 충분히 가치가 있습니다.

Back to Blog

관련 글

더 보기 »