13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] Loki

  • [k8s] Loki로 Kubernetes 로그 중앙화: 효율적인 모니터링 구축 가이드

    [k8s] Loki로 Kubernetes 로그 중앙화: 효율적인 모니터링 구축 가이드

    [k8s] Loki로 Kubernetes 로그 중앙화: 효율적인 모니터링 구축 가이드

    Kubernetes 환경을 운영하다 보면 결국 로그 때문에 한 번은 크게 삽질하게 됩니다. Pod(파드)가 재시작되면 이전 로그가 날아가고, 노드가 여러 대로 늘어나면 어디서 무슨 에러가 터졌는지 찾는 데 시간이 꽤 걸리거든요. 저도 홈랩과 실무 환경에서 비슷한 문제를 겪으면서 Loki Kubernetes 로그 구성을 진지하게 붙잡게 됐습니다. 처음엔 “그냥 kubectl logs로 보면 되지 않나?” 싶었는데, 운영 규모가 조금만 커져도 그 방식은 금방 한계가 오더라고요.

    그래서 이번 글에서는 Grafana Loki를 기준으로 Kubernetes 로그 수집과 중앙 집중형 로깅 구성을 어떻게 가져가면 좋은지, 제가 직접 해보면서 정리한 흐름으로 풀어보겠습니다. 너무 이론만 길게 가지 않고, 바로 써먹을 수 있는 형태로 설명드릴게요.

    Loki, Promtail, Grafana, Kubernetes 노드와 애플리케이션 로그 흐름을 한눈에 보여주는 전체 구성도입니다.

    Loki로 Kubernetes 로그를 모아야 하는 이유

    쉽게 말해 Loki는 로그를 저장하고 검색하기 위한 시스템입니다. 로그 전체를 무겁게 색인(indexing)하는 방식보다는, 메타데이터(label) 중심으로 다루는 접근이 특징이죠. 이게 왜 좋냐면, 운영 입장에서 필요한 로그를 비교적 효율적으로 모으고 찾는 데 유리하거든요.

    제가 처음 Loki를 붙여봤을 때 좋았던 점은 딱 세 가지였습니다.

    • Grafana(그라파나)와 궁합이 좋습니다. 로그 조회 화면이 익숙해서 진입 장벽이 낮더라고요.
    • Kubernetes 로그 수집 흐름을 만들기 편합니다. 특히 DaemonSet(데몬셋) 기반 수집기가 노드별 로그를 긁어오는 구조가 이해하기 쉬웠습니다.
    • 메트릭(metrics), 로그(logs), 추적(traces) 관측 체계를 한 방향으로 정리하기 좋습니다.

    물론 무조건 Loki만 정답은 아닙니다. Elasticsearch(엘라스틱서치) 계열이 더 맞는 조직도 있습니다. 다만 “복잡도를 조금 낮추면서 Kubernetes 로그를 중앙에서 보고 싶다”는 목적이라면 Loki는 꽤 현실적인 선택지에요.

    Grafana Loki 핵심 개념부터 먼저 잡아보겠습니다

    Loki, Promtail, Grafana 역할 구분

    구성요소 역할 운영 포인트
    Loki 로그 저장 및 조회 API 제공 라벨 설계가 중요합니다
    Promtail 노드의 로그 파일 수집 후 Loki로 전송 DaemonSet으로 배포하는 경우가 많습니다
    Grafana 로그 검색, 필터링, 시각화 처리 대시보드와 Explore 기능이 편합니다

    여기서 중요한 포인트! Promtail(프롬테일)이 하는 역할은 로그를 읽어 Loki로 보내는 수집기 일이죠. Kubernetes에서는 보통 컨테이너 로그가 노드 파일 시스템에 쌓이기 때문에, 노드마다 하나씩 떠 있는 DaemonSet이 그 로그를 읽는 구조를 많이 씁니다.

    라벨(Label)이 왜 중요할까요?

    Loki는 라벨 기반으로 로그를 찾습니다. 예를 들면 namespace, pod, container, app 같은 값들이죠. 실제로 써보니까 라벨을 너무 많이 붙이면 관리가 복잡해지고, 반대로 너무 적으면 검색이 답답하더라고요. 저도 처음엔 이것저것 다 넣었다가 쿼리가 지저분해져서 다시 정리했었습니다 ㅎㅎ

    • 자주 검색하는 기준만 라벨로 둡니다
    • 변동성이 큰 값은 라벨 남발을 피합니다
    • 운영팀이 실제로 찾는 축을 먼저 정합니다

    Kubernetes 로그 중앙화 구성 흐름

    전체 흐름은 생각보다 단순합니다.

    1. 애플리케이션 컨테이너가 표준 출력(stdout/stderr)으로 로그를 남깁니다.
    2. Kubernetes 노드가 해당 로그를 파일 형태로 보관합니다.
    3. Promtail이 노드에서 로그를 읽고 라벨을 붙입니다.
    4. Loki가 로그를 저장합니다.
    5. Grafana에서 검색하고 필터링합니다.

    이 구조가 좋은 이유는 애플리케이션 코드를 크게 건드리지 않아도 된다는 거거든요. 이미 컨테이너 표준 출력으로 로그를 잘 남기고 있다면, 인프라 쪽에서 수집 체계를 붙이기 좋습니다.

    실전 구현: Helm으로 Loki와 Promtail 배포하기

    이제 본격적으로 들어가 보겠습니다. 여기서는 많이 쓰는 Helm(헬름) 기반 예시로 설명드릴게요. 실제 운영 환경에서는 스토리지, 보존 기간, 인증, 멀티 테넌시 여부 등을 더 따져야 하지만, 처음 시작할 때는 흐름을 먼저 잡는 게 중요합니다.

    1. 네임스페이스 생성

    kubectl create namespace observability

    저는 보통 모니터링/로깅 계열 리소스를 따로 분리하려고 observability 같은 네임스페이스를 씁니다. 꼭 이 이름일 필요는 없어요.

    2. Helm 저장소 추가

    helm repo add grafana https://grafana.github.io/helm-charts
    helm repo update

    3. Loki values 파일 작성

    처음엔 기본값으로도 올라가긴 하는데, 최소한 배포 형태와 저장 방식은 눈으로 확인하고 가는 게 좋습니다.

    loki:
      auth_enabled: false
    
    singleBinary:
      replicas: 1
    
    gateway:
      enabled: true
    
    monitoring:
      dashboards:
        enabled: true
      rules:
        enabled: true

    테스트나 홈랩에서는 이렇게 단순하게 시작해도 됩니다. 다만 운영에서는 스토리지 백엔드와 고가용성 구성을 별도로 검토하셔야 합니다. 여기서 무작정 단일 인스턴스로 오래 끌고 가면 나중에 확장 시점에 다시 손이 많이 가더라고요.

    4. Loki 설치

    helm install loki grafana/loki -n observability -f loki-values.yaml

    5. Promtail values 파일 작성

    config:
      clients:
        - url: http://loki-gateway.observability.svc.cluster.local/loki/api/v1/push
    
      snippets:
        pipelineStages:
          - cri: {}
    
      positions:
        filename: /run/promtail/positions.yaml
    
      scrapeConfigs:
        - job_name: kubernetes-pods
          kubernetes_sd_configs:
            - role: pod
          relabel_configs:
            - source_labels: [__meta_kubernetes_namespace]
              target_label: namespace
            - source_labels: [__meta_kubernetes_pod_name]
              target_label: pod
            - source_labels: [__meta_kubernetes_pod_container_name]
              target_label: container
            - source_labels: [__meta_kubernetes_pod_label_app]
              target_label: app

    이 부분이 핵심입니다. 어떤 Kubernetes 메타데이터를 라벨로 가져갈지 결정하는 구간이거든요. 제가 실제로 써보니까 namespace, pod, container, app 정도부터 시작하는 게 무난했습니다.

    Kubernetes 로그 수집을 위한 Promtail과 Grafana Loki 구성도

    Promtail DaemonSet이 각 노드의 컨테이너 로그 파일을 읽고 라벨을 붙여 Loki로 보내는 흐름을 설명하는 이미지입니다.

    6. Promtail 설치

    helm install promtail grafana/promtail -n observability -f promtail-values.yaml

    7. Grafana에서 데이터 소스 연결

    Grafana를 이미 쓰고 계신다면 Loki 데이터 소스를 추가하면 됩니다. 같은 클러스터 안에 있다면 서비스 이름으로 연결하는 경우가 많습니다.

    kubectl get svc -n observability

    Grafana Explore 화면에서 Loki를 선택하고 아래처럼 조회해보면 기본 파이프라인이 제대로 도는지 확인할 수 있어요.

    {namespace="default"}

    처음 이 쿼리로 로그가 딱 뜨는 순간, 드디어 됐다! 싶은 느낌이 있습니다. 로그 중앙화는 여기서부터가 시작이거든요.

    운영하면서 유용했던 로그 쿼리 예시

    Loki는 LogQL(로그쿼리언어) 형태로 조회합니다. 익숙해지면 꽤 편합니다.

    {namespace="production", app="nginx"}
    {namespace="production", pod=~"api-.*"}
    {container="backend"} |= "error"
    {app="payments"} |= "timeout"
    • |= 는 특정 문자열 포함 검색에 자주 씁니다
    • 정규식 매칭은 필요한 곳에만 씁니다
    • 라벨 기준 필터를 먼저 좁히고 문자열 검색을 붙이면 보기가 편합니다

    이 부분은 팀 내에서 공통 조회 패턴을 만들어두면 좋습니다. 예를 들어 장애 대응 때 “namespace 먼저, app 다음, error 문자열 마지막” 같은 식으로 말이죠.

    ⚠️ 실제로 많이 겪는 문제와 트러블슈팅

    여기서부터는 제가 꽤 자주 봤던 문제들입니다. 저도 처음엔 헷갈렸는데, 한 번 원리를 이해하고 나면 금방 잡힙니다.

    1. 로그가 아예 안 들어오는 경우

    • Promtail Pod가 정상 실행 중인지 확인합니다
    • Loki push URL이 올바른지 봅니다
    • 네트워크 정책(NetworkPolicy)으로 막히지 않았는지 확인합니다
    • 애플리케이션이 파일이 아니라 표준 출력으로 로그를 남기는지 확인합니다
    kubectl get pods -n observability
    kubectl logs -n observability daemonset/promtail
    kubectl logs -n observability deploy/loki

    2. 라벨이 너무 많아져서 조회가 복잡한 경우

    이건 정말 흔합니다. Kubernetes 메타데이터를 다 가져오고 싶은 마음이 들거든요. 근데 운영해보면 자주 안 쓰는 라벨은 오히려 방해가 됩니다. 중앙 집중형 로깅의 목적은 데이터를 많이 붙이는 게 아니라, 필요한 순간 빨리 찾는 데 있다는 점을 잊지 않는 게 중요합니다.

    3. 특정 Pod 로그만 유독 안 보이는 경우

    보통 라벨 매핑 문제이거나, 애플리케이션 로그 출력 방식 차이인 경우가 많았습니다. 사이드카(sidecar)를 쓰는 구조나 멀티 컨테이너 Pod에서는 컨테이너 이름 기준으로 먼저 좁혀보는 게 좋더라고요.

    4. 과거 로그를 오래 보관하고 싶은 경우

    이건 저장소 설계와 연결됩니다. 홈랩에서는 일단 짧게 가져가도 되는데, 운영에서는 보존 정책(retention policy)을 꼭 먼저 정하셔야 합니다. 로그는 쌓이는 속도가 생각보다 빠릅니다. 처음엔 괜찮다가 어느 날 저장소가 가득 차서 당황하는 경우가 생기거든요.

    검증: Loki Kubernetes 로그가 제대로 모이는지 확인하기

    설치가 끝났다고 바로 안심하면 안 됩니다. 꼭 검증 단계를 거치셔야 합니다. 저는 아래 순서로 확인합니다.

    1. 테스트용 Pod를 띄워 의도적으로 로그를 발생시킵니다.
    2. Promtail 로그에서 수집 관련 에러가 없는지 봅니다.
    3. Grafana Explore에서 namespace와 pod 기준으로 조회합니다.
    4. 문자열 필터로 원하는 로그를 찾을 수 있는지 확인합니다.
    kubectl run log-check --image=busybox --restart=Never -- /bin/sh -c 'i=0; while true; do echo "log-check-$i"; i=$((i+1)); sleep 5; done'

    그 다음 Grafana에서 아래처럼 조회합니다.

    {pod="log-check"}

    이렇게 테스트 로그가 보이면 기본 파이프라인은 정상입니다. 이후엔 에러 패턴, 특정 앱 로그, 운영 네임스페이스 로그를 차례로 점검하면 됩니다.

    Grafana Loki로 Kubernetes 로그를 조회하는 대시보드 이미지

    Grafana Explore 또는 대시보드에서 namespace, pod, app 라벨로 로그를 필터링한 결과 예시 이미지입니다.

    비교: Loki와 다른 로그 수집 접근의 차이

    항목 Loki 중심 구성 전통적 대용량 검색 중심 구성
    초기 진입 난이도 상대적으로 단순한 편 구성 요소가 많은 편
    Grafana 연동 매우 자연스러움 별도 연계 구성이 필요할 수 있음
    라벨 설계 중요도 매우 높음 상대적으로 검색 중심 접근 가능
    홈랩/소규모 시작 부담이 덜함 조금 무거울 수 있음

    이 표를 보면 감이 오실 겁니다. “빠르게 Kubernetes 로그 중앙화를 시작하고 싶다”면 Loki가 꽤 괜찮습니다. 반대로 아주 복잡한 검색 시나리오, 대규모 장기 보관 전략, 조직 표준 스택이 이미 정해져 있다면 다른 선택지가 더 맞을 수도 있어요.

    💡 운영 팁: 제가 나중에 꼭 챙기게 된 것들

    • 라벨 최소화: 처음부터 과하게 넣지 않습니다
    • 보존 정책: 저장소 사용량을 반드시 같이 봅니다
    • 대시보드 표준화: 팀이 자주 보는 쿼리를 정리합니다
    • 애플리케이션 로그 형식: JSON 로그 여부를 팀 기준으로 맞추면 훨씬 편합니다
    • 장애 대응 문서화: “로그가 안 보일 때 체크리스트”를 만들어두면 좋습니다

    특히 JSON 형태 로그를 쓰는 팀이라면 이후 파싱과 필드 추출도 훨씬 수월해집니다. Kubernetes 로그 수집을 이렇게 중앙화하면 메트릭 모니터링과 함께 관측성(Observability, 시스템 상태를 외부 신호로 이해하는 능력)이 한 단계 올라가는 걸 체감하실 겁니다.

    중앙 집중형 로깅 도입 전후 Loki Kubernetes 로그 운영 비교 이미지

    kubectl logs 중심 운영과 Loki 기반 중앙 집중형 로깅 운영의 차이를 한눈에 정리한 비교 이미지입니다.

    자주 묻는 질문

    Q1. Kubernetes 로그 수집은 꼭 Promtail이어야 하나요?

    꼭 그렇진 않습니다. 다만 Loki와 가장 자연스럽게 엮이는 수집기로 많이 사용됩니다. 시작 단계에서는 조합이 단순한 쪽이 유지보수에 유리하더라고요.

    Q2. Grafana Loki만 설치하면 끝인가요?

    아닙니다. 저장소, 보존 정책, 접근 제어, 대시보드 표준화까지 같이 봐야 운영 품질이 올라갑니다. 설치보다 운영 기준을 세우는 게 더 중요합니다.

    Q3. 중앙 집중형 로깅이 왜 필요한가요?

    장애 대응 속도가 달라집니다. 노드와 Pod를 옮겨 다니며 로그를 찾는 시간을 줄일 수 있거든요. 특히 여러 서비스가 동시에 얽히는 환경에서는 체감 차이가 큽니다.

    마무리: Loki Kubernetes 로그 구성, 처음엔 단순하게 시작하세요

    정리해보면 Loki Kubernetes 로그 구성의 핵심은 화려한 기능보다도, 어떤 로그를 어떤 라벨로 모을지를 먼저 정하는 데 있습니다. 저도 처음엔 설정 파일만 붙잡고 씨름했었는데, 결국 답은 단순하더라고요. 필요한 로그를 빨리 찾을 수 있느냐, 장애 때 팀이 같은 화면을 보고 이야기할 수 있느냐, 그게 제일 중요했습니다.

    처음 구축하신다면 작은 범위에서 시작해보세요. 특정 네임스페이스 하나, 서비스 하나부터 붙여보고, 쿼리 패턴을 정리한 다음 확장하는 방식이 훨씬 덜 힘듭니다. 실제로 써보니까 이게 가장 덜 삽질하는 길이었습니다. 혹시 지금 Grafana Loki 도입을 고민 중이시라면, 이번 주말 홈랩에서라도 한 번 꼭 올려보세요. 생각보다 금방 감이 옵니다.

  • [k8s] OpenTelemetry K8s 모니터링, 비용 효율적인 구축 전략

    [k8s] OpenTelemetry K8s 모니터링, 비용 효율적인 구축 전략

    OpenTelemetry K8s 모니터링, 비용 효율적인 구축 전략

    안녕하세요, 13년차의 서버실 주인장입니다. 😎

    요즘 Kubernetes(쿠버네티스) 환경에서 애플리케이션을 운영하는 건 거의 기본이 되었죠. 근데 이 복잡한 환경을 제대로 모니터링하는 게 정말 쉽지 않더라고요. 특히 OpenTelemetry K8s 모니터링은 분산 시스템의 가시성(Observability)을 확보하는 데 필수적인데, 이걸 어떻게 구축해야 할지 막막한 분들이 많으실 거예요.

    비용 문제도 무시할 수 없죠. 상용 모니터링 솔루션은 비싸고, 직접 구축하려니 삽질이 이만저만이 아니거든요. 😅

    오늘은 제가 직접 Kubernetes 모니터링을 OpenTelemetry로 구축하면서 겪었던 삽질과, 어떻게 하면 비용 효율적인 구축 전략을 가져갈 수 있는지 제 경험을 바탕으로 이야기해보려 합니다. 초기엔 저도 뭐가 뭔지 헷갈렸는데, 결국 해내고 나니 뿌듯하더라고요. 함께 가시죠! 💪

    OpenTelemetry를 활용한 Kubernetes 모니터링 아키텍처는 위 그림처럼 구성할 수 있습니다. 데이터를 수집하고 백엔드로 보내는 과정이 깔끔하죠.

    개념 설명: OpenTelemetry, K8s 모니터링의 핵심

    자, 그럼 핵심 개념부터 간단히 짚고 넘어갈까요?

    • Observability(옵저버빌리티): 시스템 내부 상태를 외부에서 추론할 수 있는 능력입니다. 주로 Metrics(메트릭), Logs(로그), Traces(트레이스) 세 가지 기둥으로 구성되거든요. 이 세 가지를 제대로 봐야 시스템에서 무슨 일이 일어나는지 파악할 수 있죠.
    • OpenTelemetry(오픈텔레메트리): 이 옵저버빌리티 데이터를 수집하고, 처리하고, 내보내는 표준화된 프레임워크입니다. 벤더 종속성을 줄여주는 엄청난 장점이 있어요. 예전에는 각 모니터링 솔루션마다 에이전트를 다르게 심고 그랬었는데, OpenTelemetry 덕분에 한 번만 계측(Instrumentation)하면 다양한 백엔드로 데이터를 보낼 수 있게 된 거죠. 이게 진짜 편하더라고요!
    • Kubernetes 모니터링: K8s 클러스터 내의 Pod(파드), Node(노드), Deployment(디플로이먼트) 등의 상태와 성능을 지속적으로 관찰하는 활동입니다. CPU 사용량, 메모리, 네트워크 트래픽부터 애플리케이션 로그, 에러 트레이스까지 다 포함되거든요.
    • 비용 분석: 모니터링 솔루션은 데이터 수집량에 따라 비용이 천차만별입니다. 특히 클라우드 환경에서는 데이터 전송량, 저장량, 쿼리량 등에 따라 과금되기 때문에, 불필요한 데이터를 줄이고 효율적으로 관리하는 전략이 정말 중요하더라고요. 놓치면 배보다 배꼽이 더 커질 수 있거든요.

    실전 구현: OpenTelemetry Collector와 백엔드 구축

    이제 본격적으로 OpenTelemetry Collector를 K8s에 배포하고, 데이터를 수집하는 방법을 알아볼게요. 저는 비용 효율성을 위해 Prometheus(프로메테우스) + Grafana(그라파나) 조합으로 메트릭을, Loki(로키)로 로그를, Jaeger(예거)로 트레이스를 수집하는 방법을 선호합니다. 다 오픈소스라서 초기 비용 부담이 적거든요. 제 홈랩에서도 이 조합으로 잘 쓰고 있습니다. 👍

    먼저 OpenTelemetry Collector를 DaemonSet(데몬셋)으로 배포해서 각 노드에서 데이터를 수집하도록 설정합니다. 이게 가장 일반적이고 안정적인 방법이에요.

    # opentelemetry-collector-daemonset.yaml
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: otel-collector
      namespace: monitoring
      labels:
        app: otel-collector
    spec:
      selector:
        matchLabels:
          app: otel-collector
      template:
        metadata:
          labels:
            app: otel-collector
        spec:
          serviceAccountName: otel-collector
          containers:
          - name: otel-collector
            image: otel/opentelemetry-collector:0.87.0 # 최신 안정 버전 확인 필요합니다. 공식 도커 허브를 참고하세요!
            command: ["--config=/conf/otel-collector-config.yaml"]
            volumeMounts:
            - name: otel-collector-config-vol
              mountPath: /conf
            - name: host-proc
              mountPath: /proc
              readOnly: true
            - name: host-sys
              mountPath: /sys
              readOnly: true
            securityContext:
              privileged: true # 노드 메트릭 수집을 위해 필요할 수 있습니다. 보안에 유의하세요.
          volumes:
          - name: otel-collector-config-vol
            configMap:
              name: otel-collector-config
          - name: host-proc
            hostPath:
              path: /proc
          - name: host-sys
            hostPath:
              path: /sys
    

    다음은 ConfigMap(컨피그맵)으로 OpenTelemetry Collector의 설정을 정의합니다. 여기서 중요한 건 어떤 데이터를 수집해서 어디로 보낼지 정의하는 부분이에요. Receivers, Processors, Exporters가 핵심이죠.

    # opentelemetry-collector-config.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: otel-collector-config
      namespace: monitoring
    data:
      otel-collector-config.yaml: |
        receivers:
          otlp:
            protocols:
              grpc:
              http:
          prometheus:
            config:
              scrape_configs:
                - job_name: 'kubernetes-nodes'
                  scrape_interval: 15s
                  kubernetes_sd_configs:
                    - role: node
                  relabel_configs:
                    - action: labelmap
                      regex: __meta_kubernetes_node_label_(.+)
                    - target_label: __address__
                      replacement: kubernetes.default.svc:443
                    - source_labels: [__meta_kubernetes_node_name]
                      regex: (.+)
                      target_label: __metrics_path__
                      replacement: /api/v1/nodes/${1}/proxy/metrics
                - job_name: 'kubernetes-pods'
                  kubernetes_sd_configs:
                    - role: pod
                  relabel_configs:
                    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
                      action: keep
                      regex: true
                    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
                      action: replace
                      target_label: __metrics_path__
                      regex: (.+)
                    - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
                      action: replace
                      regex: ([^:]+)(?::\d+)?;(\d+)
                      target_label: __address__
                      replacement: $1:$2
                    - action: labelmap
                      regex: __meta_kubernetes_pod_label_(.+)
                    - source_labels: [__meta_kubernetes_namespace]
                      action: replace
                      target_label: kubernetes_namespace
                    - source_labels: [__meta_kubernetes_pod_name]
                      action: replace
                      target_label: kubernetes_pod_name
        
        processors:
          batch:
            send_batch_size: 1000
            timeout: 5s
          memory_limiter:
            limit_mib: 200
            spike_limit_mib: 50
          resourcedetection:
            detectors: [env, system, kubernetes]
            timeout: 2s
            kubernetes:
              pod_association:
                - from: cgroup
                - from: resource_attribute
                  key: k8s.pod.uid
          attributes:
            actions:
              - key: host.name
                action: delete
              - key: host.id
                action: delete
              - key: os.type
                action: delete
        
        exporters:
          prometheus:
            endpoint: "0.0.0.0:8889" # Prometheus가 이 엔드포인트를 스크래핑하여 메트릭 수집
          prometheusremotewrite:
            endpoint: "http://prometheus-server.monitoring.svc.cluster.local:9090/api/v1/write" # Prometheus Remote Write API
          otlp/logs:
            endpoint: "loki.monitoring.svc.cluster.local:3100" # Loki OTLP/HTTP Endpoint
            tls:
              insecure: true # 개발 환경에서만 사용하세요. 프로덕션에서는 TLS 구성이 필요합니다.
          otlp/traces:
            endpoint: "jaeger-collector.monitoring.svc.cluster.local:14250" # Jaeger gRPC Endpoint
            tls:
              insecure: true # 개발 환경에서만 사용하세요. 프로덕션에서는 TLS 구성이 필요합니다.
    
        service:
          pipelines:
            metrics:
              receivers: [otlp, prometheus]
              processors: [resourcedetection, attributes, batch, memory_limiter]
              exporters: [prometheus, prometheusremotewrite] # prometheus는 메트릭 노출, prometheusremotewrite는 원격 Prometheus로 전송
            logs:
              receivers: [otlp]
              processors: [resourcedetection, attributes, batch, memory_limiter]
              exporters: [otlp/logs]
            traces:
              receivers: [otlp]
              processors: [resourcedetection, attributes, batch, memory_limiter]
              exporters: [otlp/traces]
    

    여기서 exporters 부분을 보면 Prometheus, Loki, Jaeger로 데이터를 보내도록 설정한 걸 볼 수 있죠. 각 백엔드에 맞게 엔드포인트를 지정해주면 됩니다. 특히 processors 섹션에서 attributes를 사용해서 불필요한 메트릭 속성들을 제거하는 게 비용 효율적인 모니터링에 큰 도움이 되더라고요. 클라우드에서 데이터 전송량이나 저장량 줄이는 데 효과 만점입니다. 💡

    OpenTelemetry Collector와 모니터링 백엔드 상세 구성도

    OpenTelemetry Collector와 모니터링 백엔드 간의 상세 데이터 흐름 구성도입니다. 이 그림을 보면서 각 컴포넌트가 어떻게 연결되는지 쉽게 이해할 수 있을 거예요.

    주의사항/트러블슈팅: 삽질 피하기! ⚠️

    제가 이 부분에서 삽질을 좀 많이 했었습니다. 여러분은 이런 실수 안 하시길 바라면서 몇 가지 중요한 주의사항과 해결법을 공유해드릴게요. 멘토의 조언이라고 생각해주세요! 😉

    • ⚠️ 권한 문제: OpenTelemetry Collector가 노드 메트릭을 제대로 수집하려면 host-proc, host-sys 마운트와 privileged: true 설정이 필요할 수 있거든요. 보안상 민감한 부분이니 필요한 최소한의 권한만 부여하는 게 중요해요. 처음엔 권한 부족으로 메트릭이 안 들어와서 한참 헤맸습니다.
    • ⚠️ 설정 파일 오타: YAML 파일은 스페이스 하나에도 민감하죠. 특히 ConfigMap에 data 아래에 otel-collector-config.yaml: | 부분의 들여쓰기를 조심하세요. 오타 하나 때문에 Collector가 시작도 안 되는 경우가 허다하거든요. kubectl logs로 Collector Pod의 로그를 꼭 확인하세요.
    • ⚠️ 네트워크 문제: 백엔드(Prometheus, Loki, Jaeger)의 서비스 이름과 포트가 정확한지 확인해야 합니다. 특히 K8s 클러스터 내에서 service.namespace.svc.cluster.local 형태로 접근하는 게 일반적이에요. 방화벽이나 NetworkPolicy(네트워크 정책) 때문에 통신이 안 되는 경우도 많으니 kubectl exec로 Collector Pod에 들어가서 curl 등으로 연결 테스트를 해보는 게 좋습니다.
    • 💡 데이터 과부하: OpenTelemetry Collector의 memory_limiter와 batch 프로세서를 적절히 설정해서 Collector가 과도한 리소스를 사용하거나, 데이터 전송에 병목이 생기는 걸 방지해야 합니다. 저도 한 번 Collector가 메모리 폭주해서 노드가 비정상적으로 동작하는 바람에 새벽에 호출된 적이 있습니다… 😅

    검증/결과: 모니터링 대시보드 확인

    이제 모든 설정이 끝났으니, 제대로 동작하는지 확인해볼 시간입니다! 🎉 드디어 됐다! 하고 외칠 준비 되셨죠?

    1. 먼저 Grafana(그라파나)에 접속해서 Prometheus 데이터 소스를 추가하고, Kubernetes 노드/파드 메트릭 대시보드를 임포트해보세요. 저는 보통 Node Exporter Full이나 Kubernetes / Kubelet 대시보드를 사용합니다.
    2. 로그는 Loki에 쌓인 데이터를 Grafana의 Explore(탐색) 기능으로 확인하거나, Loki 전용 대시보드를 만들어 볼 수 있습니다. logcli 같은 도구로도 확인 가능하고요.
    3. 트레이스는 Jaeger UI에 접속해서 애플리케이션에서 보낸 트레이스가 잘 수집되는지 확인합니다. 서비스 이름과 오퍼레이션 이름으로 검색해보면 되겠죠.

    OpenTelemetry K8s 모니터링 Grafana 대시보드 예시

    OpenTelemetry로 수집한 Kubernetes 메트릭을 Grafana 대시보드에서 시각화한 모습입니다. 이렇게 한눈에 시스템 상태를 파악할 수 있으면 얼마나 든든한지 몰라요!

    마무리: 비용 효율과 미래를 위한 전략

    오늘은 OpenTelemetry K8s 모니터링을 비용 효율적으로 구축하는 전략에 대해 제 경험을 공유해드렸습니다.

    가장 중요한 포인트는 OpenTelemetry를 통해 특정 벤더에 종속되지 않고, 오픈소스 백엔드(Prometheus, Grafana, Loki, Jaeger)를 활용하여 초기 구축 비용을 최소화하는 것이었습니다. 이 조합은 특히 홈랩이나 소규모 프로젝트에서 빛을 발하더라고요.

    특히 OpenTelemetry Collector의 processors를 활용하여 불필요한 데이터를 필터링하고, 샘플링(Sampling) 전략을 적용하는 것이 클라우드 환경에서 비용 분석 및 절감에 큰 영향을 미친다는 점을 꼭 기억해주세요. 제가 이 부분에서 시행착오를 많이 겪었거든요. 데이터 양을 줄이는 게 진짜 중요합니다!

    Kubernetes 모니터링은 한 번 구축했다고 끝이 아닙니다. 지속적으로 데이터를 분석하고, 대시보드를 개선하며, 새로운 요구사항에 맞춰 시스템을 확장해나가야 하거든요. OpenTelemetry는 앞으로도 옵저버빌리티 분야에서 핵심적인 역할을 할 것이 분명합니다. 여러분의 환경에 맞춰 최적의 비용 효율적인 구축 전략을 찾아보시길 바랍니다. 다음 기회에 심화 내용을 다뤄볼게요! 😊

    OpenTelemetry를 활용한 비용 효율적인 Kubernetes 모니터링 이점

    OpenTelemetry를 통한 모니터링 구축은 단순히 기술적인 선택을 넘어, 장기적인 관점에서 비용 효율성과 유연성을 확보하는 전략적인 결정이 될 수 있습니다.