13년차의 서버실

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

[태그:] Prometheus

  • [AI] Triton Inference Server 프로덕션 배포 가이드와 고려사항

    [AI] Triton Inference Server 프로덕션 배포 가이드와 고려사항

    목차

    Triton Inference Server 프로덕션 배포: 도입 사례와 고려사항

    Triton Inference Server로 AI 모델 배포를 붙일 때, 문제는 대개 모델 정확도보다 운영 계약에서 먼저 터지더라고요. 개발 노트북에서는 잘 돌던 모델이 서비스에 올라가면 지연 시간(latency, 응답 지연), 동시성(concurrency, 동시 처리), 버전 교체, 헬스체크, 타임아웃 정책이 한꺼번에 얽힙니다. 저도 초반엔 “모델만 띄우면 끝”이라고 봤는데, 실제 운영에선 어떤 문제를 Triton으로 해결할지를 먼저 정하는 쪽이 훨씬 중요했습니다. 이번 글은 홈랩과 실무 검증에서 반복해서 확인한 패턴을 바탕으로, Triton을 단순한 AI 모델 서빙 엔진이 아니라 운영 경계(operational boundary)로 보는 관점에서 정리해보겠습니다.

    Triton Inference Server 기반 AI 모델 배포 아키텍처 개요 이미지

    클라이언트, 로드밸런서, Triton 서버, 모델 저장소, 모니터링까지 연결된 전체 구조를 보여주는 개요 이미지입니다.

    Triton Inference Server를 왜 보게 되나

    실무에서 Triton Inference Server가 자꾸 거론되는 이유는 단순합니다. 모델을 한 번 띄우는 건 어렵지 않은데, 같은 방식으로 오래 운영하는 일이 생각보다 어렵거든요. 프레임워크가 제각각이어도 API는 통일하고 싶고, 모델 버전은 분리하고 싶고, GPU는 놀지 않게 쓰고 싶고, 장애가 났을 때는 “서버가 죽었는지”, “모델만 실패했는지”, “큐가 막혔는지”를 빨리 구분하고 싶어집니다. Triton은 이 지점을 꽤 정직하게 해결해줍니다.

    제가 현업에서 Triton을 검토하는 기준은 기능 목록보다 아래 네 가지에 가깝습니다.

    • 모델 프레임워크가 섞여 있는데 운영 인터페이스는 하나로 가져가야 하는가
    • 실시간 추론 API와 소규모 배치 처리 요구가 한 시스템에 같이 들어오는가
    • 버전 롤백, 점진 배포, 모델 상태 점검을 서버 표준으로 묶고 싶은가
    • GPU를 여러 모델이나 여러 테넌트가 나눠 쓰는데, 감이 아니라 지표로 튜닝해야 하는가

    반대로 아래 조건이면 Triton이 과할 수 있습니다.

    • 단일 모델 하나만 낮은 트래픽으로 서비스하고 있고, 모델 교체 주기도 길다
    • 버전 병행 운영보다 애플리케이션 재배포가 더 단순하다
    • 메트릭과 큐 제어보다 구현 속도가 더 중요하다
    • CPU 기반 간단 추론만으로 충분하고, GPU 운영 복잡성을 들일 이유가 없다

    이럴 땐 FastAPI나 Flask 뒤에 모델 하나 붙이고, 앞단 리버스 프록시와 애플리케이션 메트릭만 잘 관리하는 편이 더 낫습니다. Triton은 성능 마법사가 아니라 운영 표준화 도구라서, 표준화가 아직 필요 없다면 이점도 그만큼 줄어듭니다.

    Triton Inference Server 도입 전에 먼저 정해야 하는 질문

    제가 팀에 Triton을 권할지 말지 결정할 때는 제품 요구보다 운영 질문을 먼저 던집니다.

    1. 지연 시간 상한이 빡빡한가: p95, p99 기준으로 큐잉을 얼마나 허용할지 먼저 정해야 dynamic batching을 안전하게 만질 수 있습니다.
    2. 모델 버전이 자주 바뀌는가: 교체 빈도가 높으면 모델 저장소 구조와 로드 정책부터 표준화해야 합니다.
    3. 한 GPU에 몇 개의 모델을 얹을 건가: instance_group의 count를 늘리는 순간 메모리 압박과 컨텍스트 전환 비용이 같이 따라옵니다.
    4. 장애 원인을 5분 안에 좁혀야 하는가: 이 요구가 있다면 health, stats, Prometheus metrics를 갖춘 서빙 계층이 훨씬 유리합니다.

    여기서 자주 놓치는 게 하나 있습니다. Triton은 모델 실행 속도를 빠르게 만드는 도구이기도 하지만, 실제 운영에서는 문제 위치를 빨리 찾게 해주는 도구로 더 큰 가치를 냅니다. 성능이 안 나오는 원인이 모델인지, 큐인지, 게이트웨이 타임아웃인지, 잘못된 입력 계약인지가 빨리 분리되거든요.

    핵심 개념: 모델은 올리는 게 아니라 운영하는 겁니다

    모델 저장소(Model Repository, 모델 저장소) 구조

    Triton은 모델 파일을 임의 경로에서 읽어주는 런타임이 아닙니다. 모델 저장소를 운영 단위로 본다는 점이 핵심입니다. 즉, 파일 배치 규칙이 곧 배포 규칙이 됩니다. 저도 초반에는 구조를 대충 맞췄다가 “컨테이너는 healthy인데 모델만 안 올라오는” 상태를 몇 번 겪었습니다. 그 뒤로는 모델 저장소를 코드 리뷰 대상에 포함시켰습니다.

    models/
    └── resnet50/
        ├── config.pbtxt
        ├── 1/
        │   └── model.onnx
        └── 2/
            └── model.onnx

    1, 2 같은 숫자 디렉터리가 단순 규칙처럼 보여도 운영에선 중요합니다. 버전 롤백, 병행 검증, 정책 기반 선택이 모두 이 구조에서 시작되기 때문입니다. 현업에서는 “모델 파일 교체”보다 “새 버전 디렉터리 추가 후 정책 전환”이 훨씬 덜 위험합니다.

    config.pbtxt: 성능보다 먼저 계약을 명시하는 파일

    많은 팀이 이 파일을 성능 튜닝용으로만 보는데, 저는 먼저 입력·출력 계약 명세서로 봅니다. 입력 이름, shape, 데이터 타입, 배치 허용 여부가 애플리케이션과 달라지는 순간, 서버는 살아 있어도 서비스는 실패합니다. 특히 이미지 추론에선 NHWC와 NCHW 혼동이 정말 자주 나옵니다. 클라이언트 전처리 코드와 config.pbtxt가 같은 문서를 보고 있지 않으면, 장애는 거의 반드시 다시 생기더라고요.

    dynamic batching: 처리량을 사는 대신 큐 대기를 허용하는 선택

    dynamic batching은 단순한 성능 옵션이 아닙니다. 더 정확히 말하면, GPU 효율을 높이기 위해 짧은 대기 시간을 의도적으로 허용하는 정책에 가깝습니다. 요청이 조금 모일 때까지 기다렸다가 한 번에 처리하니 처리량은 좋아질 수 있습니다. 대신 큐에서 기다리는 시간이 생기죠. 그래서 이 기능은 켜느냐 마느냐보다, 어느 정도 지연 증가를 서비스가 받아들일 수 있느냐가 먼저입니다.

    실시간 API라면 보통 max_queue_delay_microseconds를 길게 잡지 않습니다. 반대로 내부 배치성 서비스라면 queue delay를 조금 더 허용해 GPU 효율을 챙길 수 있습니다. 같은 모델이라도 서비스 성격이 다르면 정답이 달라집니다.

    instance_group: 인스턴스를 늘린다고 항상 빨라지진 않습니다

    instance_group은 같은 모델 실행 인스턴스를 CPU나 GPU에 몇 개 둘지 정하는 설정입니다. 여기서 자주 나오는 오해가 “count를 늘리면 병렬성이 늘어 성능이 무조건 좋아진다”는 생각입니다. 실제로는 모델 가중치가 인스턴스 수만큼 메모리를 더 먹고, GPU 메모리 압박이나 컨텍스트 전환 비용 때문에 응답 시간이 오히려 흔들릴 수 있습니다. 저는 이 설정을 만질 때 항상 GPU 메모리 여유, 큐 길이, compute duration 세 가지를 같이 봅니다.

    model control mode: 자동 재로딩의 편의와 운영 사고 가능성은 같이 갑니다

    이 부분은 의외로 글에서 자주 빠지는데, 운영에선 꽤 중요합니다. Triton은 모델 제어 방식을 바꿀 수 있습니다. 파일 변경을 주기적으로 감시하는 방식이 편할 때도 있지만, 프로덕션에서는 의도치 않은 재로딩이나 스토리지 지연이 문제를 만들기도 합니다. 저는 개발·실험 단계에서는 poll 기반 방식이 편하다고 보고, 운영에선 명시적 로드/언로드를 더 선호합니다. 이유는 단순합니다. 모델 교체 타이밍을 배포 파이프라인이 통제해야 장애 원인 추적이 쉬워지기 때문입니다.

    실전 구현: Triton Inference Server 최소 구성부터 올려보기

    처음 검증할 때 쿠버네티스로 바로 가는 접근은 보통 손해가 큽니다. 플랫폼 이슈와 모델 이슈가 섞여버리거든요. 저는 아래 순서로 가져가는 편입니다.

    1. 단일 Docker에서 모델 로딩 성공 여부 확인
    2. 헬스체크, 모델 상태, 메트릭 노출 확인
    3. 입력 계약과 클라이언트 payload 검증
    4. 그다음에야 Ingress, 오토스케일링, 롤링 배포 규칙 추가

    이 순서를 지키면 장애가 났을 때 “플랫폼 문제인지 모델 문제인지”를 훨씬 빨리 가를 수 있습니다.

    1. 모델 저장소와 설정 파일 만들기

    mkdir -p ./models/resnet50/1
    cp ./model.onnx ./models/resnet50/1/model.onnx
    
    cat > ./models/resnet50/config.pbtxt <<'EOF'
    name: "resnet50"
    platform: "onnxruntime_onnx"
    max_batch_size: 8
    
    input [
      {
        name: "input"
        data_type: TYPE_FP32
        dims: [ 3, 224, 224 ]
      }
    ]
    
    output [
      {
        name: "output"
        data_type: TYPE_FP32
        dims: [ 1000 ]
      }
    ]
    
    instance_group [
      {
        kind: KIND_GPU
        count: 1
      }
    ]
    
    dynamic_batching {
      preferred_batch_size: [ 4, 8 ]
      max_queue_delay_microseconds: 1000
    }
    
    version_policy: {
      latest {
        num_versions: 2
      }
    }
    EOF

    이 설정에서 운영 영향이 큰 항목은 네 가지입니다.

    • max_batch_size: 서버가 배치를 어떻게 받아들일지의 상한입니다. 값을 키우기 전에 클라이언트 요청 형식과 모델 shape가 배치를 실제로 감당하는지부터 확인해야 합니다.
    • dynamic_batching: 처리량을 끌어올리는 대신 큐 지연을 허용합니다. 실시간 추론이면 queue delay를 보수적으로 시작하는 편이 안전합니다.
    • instance_group: 병렬성뿐 아니라 GPU 메모리 사용량을 같이 바꿉니다. 메모리 부족이 나면 count 증가가 바로 비용 증가로 이어질 수 있습니다.
    • version_policy: 운영 중 남겨둘 버전 수를 제한합니다. 이걸 명시하지 않으면 저장소에 쌓인 버전이 예기치 않게 운영 면적을 넓힐 수 있습니다.

    실무에서는 config.pbtxt를 모델 산출물과 따로 보지 않고, 애플리케이션 계약 파일처럼 같이 리뷰하는 편이 훨씬 낫습니다. 모델만 바뀌었다고 생각했는데 실제로는 입력 dtype이나 shape가 바뀌는 경우가 적지 않거든요.

    Triton Inference Server 모델 저장소와 config.pbtxt 구성 설명 이미지

    모델 버전 디렉터리, config.pbtxt, 백엔드 선택, 배치 설정의 관계를 이해하기 쉽게 보여주는 구성 이미지입니다.

    2. 컨테이너 실행과 서버 상태 확인

    docker run --gpus=all --rm --name triton \
      -p 8000:8000 \
      -p 8001:8001 \
      -p 8002:8002 \
      -v $(pwd)/models:/models \
      nvcr.io/nvidia/tritonserver:24.01-py3 \
      tritonserver \
        --model-repository=/models \
        --model-control-mode=explicit \
        --load-model=* \
        --log-verbose=1

    포트는 보통 아래 역할로 씁니다.

    • 8000: HTTP endpoint
    • 8001: gRPC endpoint
    • 8002: Prometheus metrics endpoint

    여기서 한 가지 짚고 갈 점이 있습니다. 최근 운영 예시에선 config.pbtxt를 명시적으로 관리하는 쪽이 더 일반적이고, 예전 글에서 자주 보이던 --strict-model-config=true 같은 옵션은 최신 가이드 기준으로 굳이 앞세우지 않는 편이 낫습니다. 또 --model-control-mode=explicit를 쓰면 서버 시작 시 모델을 자동으로 다 올리지 않기 때문에, 위처럼 --load-model=*를 주거나 이후 API로 명시적으로 load해야 합니다. 이 차이를 놓치면 “서버는 떴는데 모델이 없다”는 상황을 바로 만나게 됩니다.

    3. 헬스체크, 개별 모델 상태, 메트릭을 분리해서 봅니다

    curl -s http://localhost:8000/v2/health/live
    curl -s http://localhost:8000/v2/health/ready
    
    curl -s http://localhost:8000/v2/models/resnet50/ready
    curl -s http://localhost:8000/v2/models/resnet50/stats
    
    curl -s http://localhost:8002/metrics | egrep "nv_inference_(request|queue|compute)"

    명시적 제어 모드에서 특정 모델만 따로 올리고 싶다면 아래처럼 repository API를 호출하면 됩니다.

    curl -s -X POST http://localhost:8000/v2/repository/models/resnet50/load

    여기서 중요한 건 ready 하나로 끝내지 않는 것입니다. 컨테이너가 ready여도 개별 모델은 로딩 실패 상태일 수 있습니다. 운영 헬스체크를 설계할 때는 컨테이너 준비 상태와 모델 가용 상태를 분리해야 합니다. 이걸 안 하면 배포는 열렸는데 특정 모델만 실패한 반쪽짜리 정상 상태가 됩니다.

    4. 초기에 꼭 보는 로그 패턴

    제가 검증 초반에 로그에서 먼저 찾는 건 세 종류입니다.

    • backend 관련 메시지: ONNX 모델인데 백엔드 선택이 어긋났거나, 모델 파일 위치가 기대 구조와 다를 때 여기서 드러납니다.
    • shape/dtype 관련 오류: 서버 설정과 클라이언트 payload 계약이 안 맞는 경우입니다.
    • model load/unload 이벤트: 의도한 시점에만 모델이 교체되는지 확인해야 합니다.

    실무에서는 서버가 떠 있는지만 보는 팀이 많습니다. 그런데 실제 장애는 “프로세스 다운”보다 계약 불일치와 큐 적체에서 더 자주 납니다.

    어떤 설정을 먼저 만질지, 비교 표로 보겠습니다

    항목 먼저 보는 상황 얻는 것 대가와 주의점
    dynamic_batching 동시 요청이 몰릴 때 GPU 활용률이 낮고 처리량이 안 나올 때 처리량 증가, GPU 활용 개선 큐 대기 시간이 늘 수 있어 실시간 API의 p95/p99를 해칠 수 있음
    max_queue_delay_microseconds 응답은 느린데 compute 시간보다 queue 시간이 먼저 커질 때 배치 효율과 지연 시간 사이 균형 조절 길게 잡으면 사용자는 “서버가 느리다”고 느끼지만 GPU는 바쁘게 보일 수 있음
    instance_group count 큐 적체가 있고 모델 병렬 실행이 실제로 필요할 때 병렬 처리 증가 가능 모델 메모리 복제, GPU 메모리 압박, 컨텍스트 전환 비용 증가 가능
    version_policy 롤백 요구가 있고 저장소에 여러 버전이 누적될 때 운영 버전 수 통제, 롤백 경로 명확화 버전 보존 전략을 배포 파이프라인과 같이 설계해야 함
    model-control-mode 모델 교체 타이밍을 엄격히 통제해야 할 때 의도한 시점에만 load/unload 수행 배포 자동화가 미흡하면 오히려 운영 절차가 번거로워질 수 있음
    HTTP vs gRPC 게이트웨이 호환성과 SDK 통일성이 중요할 때 팀 표준화 또는 고성능 연동 선택 가능 디버깅 편의, 프록시 호환성, 조직의 운영 경험을 같이 봐야 함

    제 경험상 첫 튜닝 포인트는 대개 배치와 큐입니다. 모델 최적화 전에 큐 정책을 잘못 잡아서 체감 성능을 망치는 경우를 훨씬 많이 봤습니다.

    트러블슈팅: 실제로 많이 걸리는 지점과 근본 원인

    1. 모델이 안 뜨는 경우: 파일이 아니라 운영 단위가 잘못 배치된 상태

    모델 파일을 models/resnet50/model.onnx에 바로 두는 실수는 흔합니다. 겉으로 보면 파일은 있는데, Triton 입장에선 버전이 없는 모델입니다. 운영 관점에서 보면 단순 경로 실수가 아니라 “배포 단위가 정의되지 않은 상태”에 가깝습니다. 로그에서 model version 관련 메시지가 보이면 권한보다 구조를 먼저 의심하는 편이 빠릅니다.

    2. 입력 shape 불일치: 서버 문제처럼 보이지만 계약 문제입니다

    NHWC와 NCHW 혼동, batch 차원 포함 여부, FP32와 UINT8 차이, 입력 이름 오타. 이 네 가지가 특히 잦습니다. 이때 중요한 건 서버를 재시작하는 게 아니라 클라이언트 payload와 config.pbtxt를 한 줄씩 대조하는 겁니다. readiness는 정상인데 요청만 실패하는 패턴이면, 거의 늘 계약 문제입니다.

    제가 자주 보는 실제 시나리오는 이렇습니다. 이미지 업로드 API가 애플리케이션 서버에서 전처리를 한 뒤 Triton으로 넘기는데, 전처리 코드는 NHWC 텐서를 만들고 모델은 NCHW를 기대합니다. 애플리케이션 로그에는 단순 500만 남고, 운영자는 Triton 장애로 오해합니다. 이런 건 모델 서버보다 전처리 코드와 서빙 계약을 같은 저장소에서 관리하지 않은 구조가 근본 원인입니다.

    3. 지연 시간 급증: 실행이 느린 게 아니라 큐가 길어진 경우

    실시간 추론에서 가장 헷갈리는 장애입니다. GPU 사용률은 낮거나 애매한데 응답은 느립니다. 이때는 모델 자체보다 먼저 nv_inference_queue_duration_us를 봐야 합니다. queue duration이 compute duration보다 눈에 띄게 커지면, 문제는 대개 dynamic batching 정책이나 인스턴스 병렬성 부족입니다. 반대로 compute 쪽이 크면 모델 최적화, 백엔드 선택, 하드웨어 자원 부족 쪽이 더 유력합니다.

    여기서 많이 하는 실수가 하나 있습니다. queue가 길다고 바로 instance count를 늘리는 겁니다. 모델이 무거우면 메모리가 더 들어가고, 결국 더 큰 GPU가 필요해져 비용이 올라갑니다. 먼저 queue delay, 요청 패턴, 앞단 연결 풀 크기, 게이트웨이 타임아웃을 같이 보셔야 합니다.

    4. readiness는 OK인데 서비스는 실패하는 경우

    컨테이너 readiness만 보고 배포를 열어버리면 생기는 전형적인 문제입니다. 프로세스는 살아 있고 일부 모델도 로딩됐지만, 실제로 서비스해야 하는 모델은 실패했을 수 있습니다. 운영에서는 단순 포트 체크보다 /v2/models/<name>/ready나 모델 상태 확인을 포함한 상위 헬스체크가 필요합니다. 저는 라우터가 대상 모델의 ready 여부를 확인하지 못하는 구조면, 그 구조부터 위험 신호로 봅니다.

    5. 모델 교체 때만 간헐적으로 장애가 나는 경우

    이건 성능 튜닝보다 배포 설계 문제인 경우가 많습니다. 파일 감시 기반 재로딩, 네트워크 스토리지 지연, 새 버전 업로드 중간 상태 노출이 겹치면 교체 시점에만 이상 현상이 납니다. 그래서 운영에선 새 버전 디렉터리를 완성한 뒤 명시적으로 load하는 절차가 안전합니다. 모델 파일을 덮어쓰는 방식은 복구도 추적도 둘 다 불리합니다.

    Triton Inference Server 메트릭과 실시간 추론 지연 분석 대시보드 이미지

    queue duration, compute duration, request success 지표를 함께 보고 병목을 판단하는 모니터링 예시 이미지입니다.

    검증은 이렇게 봤습니다: 응답이 왔다가 아니라, 병목 위치를 찾는 방식으로

    검증 단계에서 제가 먼저 보는 건 세 가지입니다.

    1. 헬스 상태: live, ready, 개별 모델 ready가 모두 정상인지
    2. 메트릭 이동 방향: 요청이 늘 때 queue duration과 compute duration 중 어디가 먼저 커지는지
    3. 로그 패턴: 로딩 실패, 텐서 계약 오류, 백엔드 초기화 오류가 반복되는지

    여기서 중요한 건 단순 성공률보다 병목 위치의 일관성입니다. 같은 부하 패턴에서 늘 queue가 먼저 커지면 배치 정책 문제일 가능성이 높고, 늘 compute가 먼저 치솟으면 모델 최적화나 하드웨어 부족을 의심하면 됩니다. 증상이 매번 다르면 앞단 게이트웨이, 네트워크, 클라이언트 요청 형식이 흔들리는 경우도 많습니다.

    • nv_inference_request_success가 늘어도 사용자 응답이 느리면 애플리케이션 레벨 타임아웃과 큐 대기를 같이 보셔야 합니다.
    • nv_inference_queue_duration_us가 커지면 dynamic batching의 queue delay, instance_group, 요청 분산을 우선 검토합니다.
    • nv_inference_compute_input_duration_us나 nv_inference_compute_output_duration_us가 크면 전처리·후처리 경계에서 병목이 생길 수 있습니다.
    • GPU 사용률이 낮은데 응답이 느리면 모델 엔진보다 클라이언트 연결 풀, 게이트웨이 timeout, 작은 요청 단위 반복을 먼저 의심하는 편이 맞습니다.

    저는 검증 완료 기준도 조금 보수적으로 잡습니다. 200 OK가 나오는 순간이 아니라, 요청 패턴이 바뀌어도 어느 구간이 먼저 무너지는지 설명 가능해지는 순간을 통과 기준으로 봅니다. 그때부터 운영이 덜 불안해집니다.

    언제 Triton Inference Server가 맞고, 언제 단순 구성이 더 낫나

    상황 추천 이유
    단일 모델, 낮은 트래픽, 빠른 실험 우선 앱 서버 직접 서빙 구조가 단순하고 디버깅 경로가 짧습니다. Triton의 운영 이점이 아직 크지 않습니다.
    여러 모델 병행 운영, 버전 롤백 필요 Triton 도입 모델 저장소, 버전 정책, 상태 점검, 공통 API를 한 계층으로 묶을 수 있습니다.
    GPU 자원을 여러 워크로드가 공유 Triton 우선 검토 배치, 인스턴스, 메트릭 기반 튜닝이 가능해 운영 판단이 빨라집니다.
    팀이 아직 MLOps 표준보다 기능 검증 속도를 더 중시 단일 Docker로 먼저 검증 문제 분리가 쉽고, 불필요한 플랫폼 복잡성을 늦출 수 있습니다.

    핵심은 이겁니다. 운영 표준화가 이미 필요한 팀이면 Triton이 맞고, 아직 모델 가치 검증이 먼저인 단계면 단순 구성이 더 낫습니다. 둘 다 맞는 도구인데, 맞는 시점이 다릅니다.

    실무에서 붙여둘 운영 체크리스트

    • 모델 저장소 구조를 CI 검증 대상에 넣으세요. 버전 디렉터리 규칙이 무너지면 배포 자동화가 바로 흔들립니다.
    • config.pbtxt를 모델 아티팩트와 함께 리뷰하세요. 입력 이름, dtype, shape 계약이 가장 자주 깨집니다.
    • Prometheus metrics를 기본값처럼 붙이세요. 감으로 튜닝하면 queue와 compute를 자꾸 혼동하게 됩니다.
    • 헬스체크는 컨테이너 ready만 보지 말고 개별 모델 ready를 포함하세요.
    • 모델 교체 절차는 파일 덮어쓰기보다 새 버전 디렉터리 추가 후 명시적 load/unload 쪽이 안전합니다.
    • Ingress나 API Gateway 앞단 타임아웃을 같이 보세요. 서버는 정상인데 앞단에서 먼저 끊기는 사례가 생각보다 많습니다.
    • instance_group 증가는 성능 개선안이 아니라 비용 증가안일 수도 있다는 전제로 접근하세요.

    이 체크리스트는 단순해 보여도 실제 장애 예방 효과가 큽니다. 저는 특히 모델 저장소 구조, 계약 파일, 상위 헬스체크 세 개를 먼저 잡는 편입니다. 이 셋이 정리되면 나머지 성능 튜닝은 훨씬 다루기 쉬워집니다.

    관련해서 MLOps 관측성과 모델 성능 최적화 글도 함께 보시면 흐름이 더 잘 잡힙니다. 내부 문서나 사내 기술 블로그가 있다면 이 체크리스트를 기준으로 연결해두는 것도 꽤 편합니다.

    Triton Inference Server 도입 판단 기준과 운영 체크리스트 인포그래픽

    단일 앱 서버 추론과 Triton 기반 운영을 어떤 기준으로 나눌지 한눈에 보는 요약 이미지입니다.

    자주 묻는 질문

    꼭 GPU가 있어야 하나요?

    반드시 그렇진 않습니다. 다만 Triton을 도입하는 실익은 대개 GPU 활용 최적화, 다중 모델 운영, 메트릭 기반 튜닝에서 커집니다. CPU만으로 단일 모델을 단순 서빙하는 상황이면 구조가 과할 가능성이 높습니다.

    처음부터 쿠버네티스로 가야 하나요?

    저는 권하지 않습니다. 단일 컨테이너로 모델 로딩, 상태 확인, 메트릭 노출, 입력 계약 검증까지 끝낸 뒤에 오케스트레이션으로 넘어가는 편이 낫습니다. 플랫폼 문제가 끼어들면 장애 원인 분리가 어려워집니다.

    실시간 추론에 dynamic batching을 켜도 되나요?

    됩니다. 다만 처리량만 보고 켜면 안 되고, queue delay를 짧게 시작한 뒤 p95, p99 지연과 queue duration 변화를 함께 보면서 조정하셔야 합니다. 사용자가 느끼는 느림은 compute보다 queue에서 더 자주 생깁니다.

    모델 버전은 많이 남겨둘수록 안전한가요?

    항상 그렇진 않습니다. 롤백 여지는 늘어나지만, 저장소 관리 범위와 운영 복잡성도 같이 커집니다. 운영에 필요한 수만 남기고, 버전 정책을 배포 파이프라인과 함께 관리하는 편이 더 안정적입니다.

    마무리: 이런 경우엔 Triton이 맞고, 이런 경우엔 단순 구성이 낫습니다

    여러 모델을 함께 운영해야 하고, 버전 교체와 롤백이 잦고, 실시간 추론과 처리량 사이에서 정책 결정을 계속해야 한다면 Triton Inference Server는 꽤 강한 선택지입니다. 특히 운영 중 문제를 성능, 계약, 배포, 관측성 관점으로 분리해 다뤄야 하는 팀이라면 더 그렇습니다.

    반대로 단일 모델 하나를 낮은 트래픽으로 빠르게 붙이는 단계라면, Triton이 기술적으로 가능하더라도 조직적으로는 과할 수 있습니다. 이럴 땐 앱 서버 직접 서빙이 더 낫습니다. 제 권장은 분명합니다. MLOps 요구가 이미 생겼다면 Triton부터 검토하시고, 아직 검증 단계라면 단일 Docker에서 성공 기준을 먼저 만든 뒤 확장하세요. 결국 중요한 건 화려한 기능보다 운영 계약을 어디까지 표준화해야 하느냐입니다. 이 질문이 생기는 순간, Triton은 제값을 합니다.

  • [k8s] Prometheus Operator vs 직접 설정: Kubernetes 모니터링 실전 비교 분석

    [k8s] Prometheus Operator vs 직접 설정: Kubernetes 모니터링 실전 비교 분석

    Prometheus Operator vs 직접 설정: Kubernetes 모니터링 실전 비교 분석

    쿠버네티스 운영을 조금만 해보면 결국 만나게 되는 질문이 있습니다. Prometheus Operator vs 직접 설정, 대체 뭐가 더 낫냐는 거죠. 저도 처음엔 “Prometheus(프로메테우스, 시계열 메트릭 모니터링 시스템)면 그냥 띄우면 되는 거 아닌가?” 싶었는데, 실제로 홈랩과 운영 환경에서 둘 다 굴려보니 생각보다 차이가 꽤 크더라고요. 특히 Kubernetes 모니터링을 제대로 붙이려면 서비스 디스커버리(Service Discovery, 대상 자동 발견), 알림 규칙(Alerting Rules, 경고 조건), 그리고 Grafana 연동까지 자연스럽게 이어져야 하거든요.

    이번 글에서는 제가 직접 삽질했던 경험을 바탕으로, Prometheus Operator 방식과 직접 설정 방식을 현실적으로 비교해보겠습니다. 단순히 “이게 더 최신이라 좋다” 같은 얘기는 빼고, 실제 운영 관점에서 어디가 편하고 어디서 귀찮아지는지 정리해볼게요.

    Prometheus Operator와 직접 설정 방식이 쿠버네티스 클러스터 안에서 어떻게 다르게 배치되는지 보여주는 아키텍처 이미지입니다.

    왜 이 비교가 중요한가: Kubernetes 모니터링에서 운영 비용이 갈립니다

    모니터링은 처음 붙일 때보다 나중에 유지보수할 때 진가가 드러납니다. 초반에는 둘 다 잘 돌아가는 것처럼 보여요. 근데 클러스터가 커지고, 애플리케이션이 늘고, 팀원이 늘어나면 설정 방식의 차이가 운영 비용으로 바로 튀어나옵니다.

    • 직접 설정은 구조를 깊게 이해하기 좋고, 제어권이 높습니다.
    • Operator 방식은 선언형(Declarative, 원하는 상태를 정의하는 방식) 운영이 편하고 확장성이 좋습니다.
    • 작은 홈랩에서는 직접 설정이 빠를 때도 있지만, 팀 단위 운영에서는 Operator가 훨씬 덜 피곤한 경우가 많습니다.

    제가 처음 직접 설정으로 시작했을 때는 설정 파일 하나만 고치면 끝날 줄 알았거든요. 근데 대상 서비스가 늘어나고 scrape job이 많아지니까, 어느 순간 prometheus.yml이 점점 거대해졌습니다. 그때부터 “아 이건 사람이 계속 손으로 관리할 구조가 아니구나” 싶더라고요.

    쉽게 말해: Prometheus Operator vs 직접 설정의 핵심 차이

    쉽게 말해, Prometheus Operator는 Prometheus 자체를 쿠버네티스 리소스(Custom Resource, 사용자 정의 리소스)로 관리하게 해주는 방식입니다. 반대로 직접 설정은 Deployment, ConfigMap, ServiceAccount 같은 리소스를 직접 만들고, scrape 설정도 내가 직접 관리하는 방식입니다.

    항목 Prometheus Operator 직접 설정
    설정 관리 ServiceMonitor, PodMonitor, PrometheusRule 같은 CRD 기반 prometheus.yml 직접 수정
    초기 진입 난이도 처음엔 다소 생소함 개념만 알면 바로 시작 가능
    확장성 매우 좋음 대상이 많아질수록 불편
    운영 자동화 높음 낮음
    문제 추적 리소스 구조 이해 필요 설정 파일 기준으로 단순함
    팀 협업 표준화하기 좋음 작성자 의존도가 높아짐

    여기서 중요한 포인트! 둘 중 하나가 절대적으로 우월하다기보다는, 클러스터 규모와 운영 방식에 따라 유리한 선택이 달라집니다. 저도 작은 테스트 클러스터에서는 직접 설정을 아직도 씁니다. 빠르게 확인하기 좋거든요.

    언제 어떤 방식을 고르면 좋은가

    Prometheus Operator가 잘 맞는 경우

    • 여러 네임스페이스(namespace, 논리적 격리 단위)의 워크로드를 지속적으로 모니터링해야 할 때
    • 팀원이 늘어나서 모니터링 리소스를 표준화해야 할 때
    • Alertmanager(알림 관리자), Grafana, rules 관리를 함께 묶고 싶을 때
    • Helm(헬름, 쿠버네티스 패키지 매니저) 기반 운영에 익숙할 때

    직접 설정이 잘 맞는 경우

    • 학습 목적이나 홈랩처럼 단순한 구조일 때
    • Prometheus 내부 설정을 세밀하게 직접 다루고 싶을 때
    • CRD를 추가하고 싶지 않을 때
    • 문제 발생 시 설정 파일 한 장으로 빠르게 디버깅하고 싶을 때

    사실 처음 배울 때는 직접 설정이 개념 잡기 좋습니다. Prometheus가 어떻게 scrape하고, 어떤 target을 찾고, 어떤 식으로 저장하는지 몸으로 익히게 되거든요. 반대로 운영 단계에서는 Operator가 진짜 편해집니다. 이거 써보면 “아, 사람이 yaml 몇 천 줄 들고 싸우면 안 되는구나” 싶습니다 ㅎㅎ

    실전 구현 1: Prometheus Operator로 Kubernetes 모니터링 구성

    제가 보통 가장 무난하게 시작하는 방식은 kube-prometheus-stack 차트를 쓰는 겁니다. Prometheus, Alertmanager, Grafana를 한 번에 올리기 좋고, 커뮤니티에서 널리 쓰는 편이라 자료도 많습니다.

    1. 모니터링 전용 네임스페이스를 생성합니다.
    2. Helm 저장소를 추가합니다.
    3. 차트를 설치합니다.
    4. ServiceMonitor로 수집 대상을 선언합니다.
    kubectl create namespace monitoring
    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update
    helm install monitoring prometheus-community/kube-prometheus-stack -n monitoring

    설치가 끝나면 Prometheus와 Grafana가 함께 배포됩니다. 여기까지는 꽤 부드럽게 갑니다. 진짜 체감 포인트는 그 다음부터예요. 애플리케이션 하나 추가할 때마다 prometheus.yml을 직접 안 만지고, ServiceMonitor만 선언하면 되거든요.

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      name: sample-app
      namespace: monitoring
    spec:
      selector:
        matchLabels:
          app: sample-app
      namespaceSelector:
        matchNames:
          - app-space
      endpoints:
        - port: metrics
          path: /metrics
          interval: 30s

    이 방식의 장점은 명확합니다. 애플리케이션 쪽 Service에 라벨만 잘 붙어 있으면, 모니터링 설정이 애플리케이션 배포 흐름에 자연스럽게 붙습니다. GitOps(Git옵스, Git 기반 선언형 운영) 하시는 분들이 Operator를 좋아하는 이유가 여기 있습니다.

    ServiceMonitor가 서비스 라벨을 기준으로 메트릭 수집 대상을 찾아가는 흐름을 보여주는 구성 다이어그램입니다.

    실전 구현 2: Prometheus 직접 설정으로 구성하기

    이번엔 직접 설정입니다. 이 방식은 Prometheus가 어떻게 동작하는지 이해하기엔 정말 좋습니다. 저도 처음 구조를 배울 때는 이 방법으로 오래 굴렸습니다. 다만 규모가 커지면 금방 손이 많이 가더라고요.

    1. Prometheus 설정을 담을 ConfigMap을 만듭니다.
    2. RBAC(Role-Based Access Control, 역할 기반 권한 제어)를 설정합니다.
    3. Deployment와 Service를 배포합니다.
    4. targets 페이지에서 수집 상태를 확인합니다.
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: prometheus-config
      namespace: monitoring
    data:
      prometheus.yml: |
        global:
          scrape_interval: 30s
        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
              - 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+)
                replacement: $1:$2
                target_label: __address__
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: prometheus
      namespace: monitoring
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: prometheus
      template:
        metadata:
          labels:
            app: prometheus
        spec:
          serviceAccountName: prometheus
          containers:
            - name: prometheus
              image: prom/prometheus
              args:
                - --config.file=/etc/prometheus/prometheus.yml
              ports:
                - containerPort: 9090
              volumeMounts:
                - name: config
                  mountPath: /etc/prometheus
          volumes:
            - name: config
              configMap:
                name: prometheus-config

    직접 설정의 핵심은 relabel_configs를 이해하는 겁니다. 이 부분이 처음엔 진짜 벽처럼 느껴집니다. 저도 여기서 꽤 오래 멈췄었어요. 왜 target이 안 잡히는지 몰라서 annotation(어노테이션, 메타데이터) 오타 하나 찾겠다고 한참 봤던 기억이 납니다.

    대신 이 방식은 구조가 명확합니다. 어떤 설정이 왜 들어갔는지 한 줄씩 따라갈 수 있어요. 학습용으로는 정말 좋습니다.

    Grafana 연동은 어떻게 보나

    Grafana 연동은 두 방식 모두 어렵지 않습니다. 차이는 연결보다도 대시보드와 데이터소스(Data Source, 데이터 공급원) 관리 방식에서 납니다. Operator 스택을 쓰면 Grafana가 함께 올라오는 경우가 많아서 시작이 빠릅니다. 직접 설정은 Prometheus만 먼저 올리고 Grafana를 따로 배포하는 흐름이 일반적입니다.

    kubectl port-forward svc/monitoring-grafana -n monitoring 3000:80
    kubectl port-forward svc/prometheus -n monitoring 9090:9090

    Grafana에서 Prometheus URL을 연결한 뒤, Kubernetes 관련 대시보드를 붙이면 CPU, 메모리, Pod 재시작 수, 노드 상태 등을 한눈에 볼 수 있습니다. 드디어 됐다! 하는 순간이 여기서 오죠. 숫자가 그래프로 보이기 시작하면, 그전까지는 안 보이던 병목이 갑자기 눈에 들어옵니다.

    ⚠️ 실제 겪었던 문제와 트러블슈팅

    여기서부터가 진짜 운영입니다. 설치보다 문제 해결이 더 중요하거든요.

    1. ServiceMonitor를 만들었는데 target이 안 잡힐 때

    • Service 라벨과 ServiceMonitor selector가 일치하는지 확인합니다.
    • metrics 포트 이름이 ServiceMonitor의 endpoints.port와 같은지 봅니다.
    • namespaceSelector가 실제 애플리케이션 네임스페이스를 포함하는지 체크합니다.

    이건 제가 꽤 자주 겪었습니다. 특히 포트 번호가 아니라 포트 이름으로 매칭한다는 걸 놓치면 한참 헤매게 됩니다.

    2. 직접 설정에서 scrape가 안 될 때

    • Pod annotation 키가 정확한지 봅니다.
    • RBAC 권한이 충분한지 확인합니다.
    • Prometheus UI의 Status > Targets에서 에러 메시지를 먼저 봅니다.

    처음엔 Prometheus 로그부터 뒤졌는데, 실제로는 Targets 화면이 더 빠르더라고요. 여기서 중요한 포인트! 모니터링 장애는 대개 설정 오타나 권한 누락에서 시작합니다.

    3. Grafana에 데이터가 안 보일 때

    • Prometheus 데이터소스 URL이 맞는지 확인합니다.
    • Prometheus 쿼리(PromQL, 프로메테우스 질의 언어)에서 메트릭이 실제로 조회되는지 먼저 봅니다.
    • 시간 범위(Time Range)가 너무 짧지 않은지 확인합니다.

    이건 별거 아닌데 은근 자주 나옵니다. 수집은 되고 있는데, 대시보드 시간 범위가 안 맞아서 “왜 빈 화면이지?” 하고 멍해지는 경우가 있거든요. 저도 몇 번 당했습니다 ㅎㅎ

    검증과 결과: 운영해보면 어떤 차이가 나나

    결론부터 말하면, Prometheus Operator vs 직접 설정은 단순한 기능 비교가 아니라 운영 방식의 선택에 가깝습니다.

    관점 Operator 직접 설정
    빠른 시작 Helm 기반으로 빠름 구성요소를 이해하면 빠름
    변경 관리 리소스 단위로 분리되어 편함 중앙 설정 파일이 비대해지기 쉬움
    문제 분석 CRD 구조 이해가 필요 설정 파일 기준으로 직관적
    확장 운영 유리함 점점 수동 작업 증가
    학습 가치 운영 패턴 학습에 좋음 Prometheus 내부 구조 학습에 좋음

    제가 실제로 써보니까, 작은 테스트 환경에서는 직접 설정이 부담이 적었습니다. 반면 운영 서비스가 두세 개를 넘어가고, 여러 네임스페이스에 exporter(exporter, 메트릭 노출 구성요소)가 붙기 시작하면 Operator 쪽이 확실히 편해집니다. 특히 팀원이 함께 건드리는 순간부터 차이가 커져요.

    Grafana 연동 결과로 Kubernetes 모니터링 대시보드를 보여주는 이미지

    Grafana 대시보드와 Prometheus 타깃 상태 화면을 함께 보여주는 결과 검증 이미지입니다.

    자주 묻는 질문 정리

    Q1. 입문자는 어떤 방식부터 시작하는 게 좋을까요?

    제가 추천하는 순서는 이렇습니다. 먼저 직접 설정으로 구조를 이해하고, 운영에는 Operator를 쓰는 방식입니다. 둘 중 하나만 알면 나중에 막힐 때 원인 파악이 어렵더라고요.

    Q2. 무조건 Operator가 정답인가요?

    그건 아닙니다. 싱글 클러스터 홈랩이나 짧은 실험 환경에서는 직접 설정이 더 가볍고 빠를 수 있습니다. 특히 CRD 추가를 최소화하고 싶다면 여전히 좋은 선택입니다.

    Q3. Grafana까지 꼭 같이 써야 하나요?

    필수는 아니지만, 실전에서는 거의 같이 갑니다. Prometheus가 수집과 저장을 담당하고, Grafana가 시각화를 담당하니까 역할이 깔끔하게 나뉘거든요.

    정리: 지금 선택해야 한다면 저는 이렇게 갑니다

    Kubernetes 모니터링을 장기적으로 운영할 계획이라면 저는 대체로 Operator를 권합니다. 선언형 리소스로 관리되고, 팀 협업에도 잘 맞고, 알림 규칙과 확장도 편하거든요. 반대로 학습 목적이 강하거나, 작은 홈랩에서 구조를 이해하고 싶다면 직접 설정으로 한 번 부딪혀보는 것도 아주 좋습니다. 저도 그렇게 배우면서 삽질 좀 했습니다. 근데 그 삽질 덕분에 지금은 문제가 생겨도 어디를 먼저 봐야 하는지 감이 오더라고요.

    혹시 지금 Prometheus Operator vs 직접 설정 사이에서 고민 중이시라면, 질문을 이렇게 바꿔보시면 결정이 쉬워집니다. “내가 지금 배우고 싶은가, 아니면 오래 운영하고 싶은가?” 이거거든요. 답이 전자면 직접 설정, 후자면 Operator 쪽이 보통 맞습니다.

    Prometheus Operator vs 직접 설정 선택 기준을 요약한 비교 이미지

    두 방식의 장단점과 추천 사용 시나리오를 한눈에 요약한 인포그래픽 이미지입니다.

    다음 글에서는 Alertmanager(알림 관리자)와 Slack 같은 채널 연동, 그리고 PromQL 기초 쿼리를 다뤄볼 예정입니다. 이전 글에서 exporter 구성 방법을 보셨다면 이번 내용이 더 잘 이어질 거예요. ✅

  • [모니터링] Grafana Cloud 비용 분석, 자체 Prometheus로 돌아간 이유

    [모니터링] Grafana Cloud 비용 분석, 자체 Prometheus로 돌아간 이유

    [모니터링] Grafana Cloud 비용 분석, 자체 Prometheus로 돌아간 이유

    Grafana Cloud 비용이 예전보다 훨씬 민감하게 느껴지기 시작하면, 그때부터는 단순히 ‘관리형이라 편하다’만으로 설명이 안 되더라고요. 저도 홈랩과 소규모 운영 환경에서 Grafana Cloud를 꽤 편하게 썼었는데, 메트릭(Metrics, 시계열 지표)과 로그(Logs, 시스템/애플리케이션 기록)가 늘어나면서 청구 구조를 다시 뜯어보게 됐습니다. 특히 Grafana Cloud 비용은 사용량이 조금만 늘어도 체감상 훅 올라갈 수 있어서, 모니터링 비용을 어디까지 SaaS로 맡길지 진지하게 다시 보게 되거든요.

    이번 글은 ‘무조건 자체 호스팅이 낫다’는 이야기가 아닙니다. Grafana Cloud 공식 가격 구조를 기준으로 왜 비용이 커지는지, 그리고 어떤 조건에서 자체 호스팅 ROI(Return on Investment, 투자 대비 효과)가 맞아떨어지는지 제가 정리한 기준을 공유해보려는 글입니다. 중간에 실제로 바로 올려볼 수 있는 Prometheus(프로메테우스, 메트릭 수집기) + Grafana(그라파나, 시각화 도구) 구성 예시도 넣어둘게요.

    Grafana Cloud와 자체 Prometheus 구성을 비용 관점에서 비교한 전체 아키텍처 예시입니다.

    1. 왜 Grafana Cloud 비용이 갑자기 아프게 느껴질까

    처음엔 진짜 편합니다. 가입하고, 에이전트 붙이고, 대시보드 몇 개 열면 끝이거든요. 저도 처음엔 이게 뭔가 싶을 정도로 진입 장벽이 낮아서 아주 만족했었습니다. 근데 여기서 중요한 포인트가 있습니다. 편한 구조일수록 과금 단위가 눈에 잘 안 들어온다는 점입니다.

    Grafana 공식 가격 페이지를 보면, Pro 플랜은 월 플랫폼 요금(platform fee)에 더해 사용량 기반 과금이 붙습니다. 메트릭은 active series(액티브 시리즈, 실제로 수집 중인 시계열 개수) 기준이고, 로그와 트레이스는 process / write / retain처럼 단계별 과금 구조가 걸려 있더라고요. 쉽게 말해, 데이터를 많이 넣는 환경에서는 ‘조금 늘었네’라고 생각했는데 청구서는 전혀 조금이 아닐 수 있다는 뜻입니다.

    • 메트릭: active series가 늘면 비용이 바로 반응합니다.
    • 로그: 수집량뿐 아니라 처리와 저장이 분리돼 보여서 체감이 더 큽니다.
    • 트레이스: 장애 분석엔 좋지만, 운영 습관 없이 켜두면 금방 비싸집니다.
    • 보존 기간(retention, 데이터 보관 기간): 길어질수록 관리형 서비스의 장점은 커지지만 비용도 같이 올라갑니다.

    이런 구조 때문에 클라우드 가격이 ‘갑자기 2배 오른 느낌’으로 다가오는 경우가 많습니다. 꼭 단가만 오른 게 아니라, 내가 보내는 데이터 패턴과 과금 기준이 맞물리면서 총액이 급격히 커지는 거죠. 실제로 써보니까, 비용 문제는 제품 성능보다 카디널리티(cardinality, 라벨 조합 폭발) 관리 실패에서 먼저 터지는 경우가 많더라고요.

    2. Grafana Cloud 가격 구조를 쉽게 풀어보면

    공식 가격 페이지 기준으로 현재 눈에 띄는 포인트는 이렇습니다. 글을 읽는 시점에 바뀔 수 있으니, 실제 계약 전에 공식 페이지는 꼭 다시 확인하셔야 합니다.

    항목 공식 페이지 기준 포인트 운영자가 봐야 할 부분
    Metrics Free는 월 10k active series, 14일 보관 라벨 설계가 나쁘면 금방 초과합니다.
    Metrics Pro 월 플랫폼 요금 + 사용량 기반 가격 노드 수보다 series 폭증이 더 위험합니다.
    Logs Free 월 50GB, 14일 보관 테스트 환경은 괜찮지만 운영 로그는 빠듯할 수 있습니다.
    Logs Pro process, write, retain 기반 사용량 과금 수집, 저장, 보관을 따로 봐야 합니다.
    Retention Pro 기준 metrics 13개월, logs/traces 30일 장기 보관이 필요한 조직엔 장점이 큽니다.

    쉽게 말해 이렇습니다. Grafana Cloud 비용은 서버 대수보다도 ‘얼마나 많은 시계열과 데이터를 계속 보내고 있는가’에 더 민감합니다. VM 몇 대 수준에서는 괜찮아 보여도, 쿠버네티스(Kubernetes, 컨테이너 오케스트레이션) 들어가고 라벨이 늘고, 로그를 구조화해서 많이 쌓기 시작하면 얘기가 달라집니다.

    그래서 저는 비용 분석할 때 아래 세 가지부터 봅니다.

    1. active series가 왜 늘고 있는지
    2. scrape interval(스크랩 주기, 수집 간격)이 과한지
    3. 꼭 SaaS에 남겨야 하는 데이터와 로컬에 둬도 되는 데이터를 구분했는지

    3. 자체 호스팅 ROI, 저는 이렇게 계산합니다

    여기서 많이들 실수하는 게 있습니다. 자체 Prometheus로 돌린다고 해서 무조건 싸지 않거든요. 저도 처음엔 ‘VM 하나면 끝 아닌가?’ 싶었는데, 막상 해보면 백업, 디스크, 알람, 업그레이드, 장애 대응까지 다 내 일이 됩니다. 삽질 좀 했습니다 ㅎㅎ

    그래도 자체 호스팅 ROI가 좋아지는 구간은 분명히 있습니다.

    • 메트릭은 많은데 장기 보관이 꼭 필요하지 않을 때
    • 운영 인력이 있어 기본 유지보수를 감당할 수 있을 때
    • 로그와 트레이스를 전부 관리형으로 둘 필요가 없을 때
    • 홈랩, 사내 관제, 내부 서비스처럼 외부 SLA보다 비용 통제가 더 중요할 때

    반대로 아래 조건이면 Grafana Cloud가 여전히 훨씬 편할 수 있습니다.

    • 24×7 대응과 장기 보관이 중요할 때
    • 멀티 리전, 팀 협업, 권한 관리가 이미 복잡할 때
    • 장애 나면 관제 스택을 직접 고칠 사람이 없을 때

    제가 실제로는 이렇게 따집니다. 월 청구서 증가분과 직접 운영할 때 들어가는 VM/디스크/백업 비용 + 관리 시간을 같이 봅니다. 숫자를 억지로 예쁘게 만들 필요는 없고요. 한 달에 두세 번만 대시보드 보고, 보관 기간도 15일~30일이면, 자체 Prometheus 쪽이 생각보다 금방 수지가 맞는 경우가 있습니다.

    4. 그래서 저는 Prometheus + Grafana 조합으로 다시 갔습니다

    이번 선택의 핵심은 단순했습니다. 메트릭은 자체 호스팅, 필요하면 나중에 일부만 외부로 보낸다. Prometheus는 구조가 명확하고, Grafana는 익숙하고, 둘 다 문서가 탄탄합니다. 무엇보다 제가 어디서 비용이 나는지 눈으로 볼 수 있더라고요.

    Prometheus 공식 문서를 보면 로컬 저장소(local storage)는 기본적으로 15일 retention입니다. 그리고 저장소 크기를 제어하려면 --storage.tsdb.retention.time 또는 --storage.tsdb.retention.size를 잡을 수 있습니다. 또 중요한 경고가 하나 있는데, NFS 같은 비POSIX 환경은 권장되지 않습니다. 이거 모르고 네트워크 스토리지에 올렸다가 애매한 문제 겪는 경우 진짜 많습니다.

    Grafana Cloud 비용 절감을 위해 구성한 자체 Prometheus 홈랩 다이어그램

    Docker Compose 기반으로 Prometheus와 Grafana를 엮은 홈랩 구성 예시입니다.

    5. 실전 구현: Docker Compose로 10분 안에 올리기

    복잡하게 시작할 필요 없습니다. 가장 단순하고 관리하기 쉬운 형태로 먼저 띄우는 게 좋습니다. 아래 예시는 Prometheus와 Grafana를 같은 Docker Compose 네트워크에 올리는 방식입니다.

    5-1. 디렉터리 구조

    monitoring/
    ├── docker-compose.yaml
    ├── prometheus/
    │   └── prometheus.yml
    └── grafana/
        └── provisioning/
            └── datasources/
                └── prometheus.yaml

    5-2. docker-compose.yaml

    services:
      prometheus:
        image: prom/prometheus:latest
        container_name: prometheus
        restart: unless-stopped
        command:
          - --config.file=/etc/prometheus/prometheus.yml
          - --storage.tsdb.path=/prometheus
          - --storage.tsdb.retention.time=15d
          - --storage.tsdb.retention.size=20GB
          - --web.enable-lifecycle
        ports:
          - "9090:9090"
        volumes:
          - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
          - prometheus-data:/prometheus
    
      grafana:
        image: grafana/grafana:latest
        container_name: grafana
        restart: unless-stopped
        ports:
          - "3000:3000"
        volumes:
          - grafana-data:/var/lib/grafana
          - ./grafana/provisioning:/etc/grafana/provisioning:ro
        depends_on:
          - prometheus
    
    volumes:
      prometheus-data:
      grafana-data:

    여기서 중요한 포인트는 두 가지입니다. 첫째, retention.time과 retention.size를 둘 다 넣어 디스크 폭주를 막는 것. 둘째, 영속 볼륨(persistent volume)을 꼭 쓰는 것입니다. 안 그러면 컨테이너 다시 뜰 때 데이터가 날아가거든요.

    5-3. prometheus.yml

    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    
    scrape_configs:
      - job_name: prometheus
        static_configs:
          - targets:
              - prometheus:9090

    Prometheus 공식 시작 가이드의 가장 기본적인 예시는 자기 자신을 스크랩하는 구성입니다. 저는 처음에 딱 여기서 시작하시는 걸 추천합니다. 이것만으로도 Prometheus가 정상 수집 중인지 바로 검증할 수 있거든요.

    5-4. Grafana 데이터소스 프로비저닝

    apiVersion: 1
    
    datasources:
      - name: Prometheus
        type: prometheus
        access: proxy
        url: http://prometheus:9090
        isDefault: true
        jsonData:
          httpMethod: POST

    Grafana 공식 문서에도 나오지만, 같은 Compose 네트워크라면 http://prometheus:9090처럼 서비스 이름으로 붙이는 방식이 제일 깔끔합니다. 많은 분들이 여기서 localhost:9090 넣고 왜 안 되지? 하는데, 컨테이너 안에서 localhost는 자기 자신이거든요. 저도 처음엔 여기서 한 번 헷갈렸습니다.

    5-5. 실행

    cd monitoring
    docker compose up -d
    
    docker compose ps
    curl http://localhost:9090/-/ready
    curl http://localhost:3000/api/health

    Prometheus는 http://localhost:9090, Grafana는 http://localhost:3000으로 들어가면 됩니다. Grafana 데이터소스가 자동으로 붙어 있으면 거의 다 된 겁니다. 드디어 됐다! 하는 순간이 여기서 오더라고요.

    Grafana Cloud 비용 대안으로 자체 Prometheus를 연결한 Grafana 설정 이미지

    Grafana에서 Prometheus 데이터소스가 정상 연결된 상태를 보여주는 설정 화면 예시입니다.

    6. 운영하면서 꼭 챙겨야 하는 비용 절감 포인트

    자체 호스팅으로 돌아왔다고 모니터링 비용 문제가 자동 해결되진 않습니다. 그냥 청구서 대신 디스크와 리소스가 문제를 말해줄 뿐이죠. 그래서 아래 기준은 꼭 잡고 가는 편이 좋습니다.

    1. scrape interval을 무작정 5초로 두지 않습니다. 15초나 30초면 충분한 경우가 많습니다.
    2. high cardinality 라벨을 줄입니다. 요청 ID, 세션 ID 같은 값은 거의 독입니다.
    3. 장기 보관이 필요하면 Prometheus 단독보다 Thanos, Mimir 같은 별도 구조를 검토합니다.
    4. 메트릭과 로그를 분리해서 생각합니다. 둘을 한 번에 SaaS에서 빼면 운영 복잡도가 급격히 올라갈 수 있습니다.

    특히 모니터링 비용은 수집량보다도 라벨 설계에서 무너지는 경우가 많습니다. 예를 들어 pod 이름, request path, 사용자별 식별자가 섞이면 active series가 순식간에 불어납니다. 클라우드 가격이 비싸다고 느껴질 때는 서비스 갈아타기 전에 먼저 series 폭증 원인을 보는 게 맞습니다. 이게 정말 중요한 포인트입니다!

    7. ⚠️ 실제로 많이 겪는 트러블슈팅

    • Grafana에서 데이터가 안 보임
      원인: 데이터소스 URL을 localhost:9090으로 넣은 경우가 많습니다. 컨테이너 분리 환경이면 서비스명이나 내부 네트워크 주소를 써야 합니다.
    • 디스크가 생각보다 빨리 참
      원인: retention은 시간만 잡고 size 제한을 안 둔 경우가 많습니다. --storage.tsdb.retention.size를 같이 설정하세요.
    • Prometheus 재시작 후 데이터가 날아감
      원인: 볼륨 마운트가 빠졌을 가능성이 큽니다. 특히 테스트하다가 귀찮아서 빼면 꼭 나중에 후회합니다.
    • NFS에 올렸더니 이상하게 불안정함
      원인: Prometheus 공식 문서에서도 로컬 파일시스템 사용을 강하게 권장합니다. 네트워크 파일시스템은 피하는 편이 안전합니다.

    저는 한때 백업 편하겠다고 네트워크 스토리지를 먼저 떠올렸었는데, 이건 운영 편의보다 안정성이 우선이더라고요. 결국은 로컬 디스크 + 스냅샷/백업 전략으로 다시 정리했습니다.

    8. 검증 결과: 무엇이 좋아졌고 무엇을 잃었나

    직접 운영으로 바꾸고 나면 제일 먼저 느끼는 건 비용 예측 가능성입니다. Grafana Cloud 비용처럼 사용량 급등에 따라 청구서가 튀는 대신, 이제는 VM 크기와 디스크 크기, retention 정책으로 상한선을 제가 결정할 수 있습니다. 이거 진짜 편하더라고요. 적어도 월말에 놀랄 일은 줄어듭니다.

    반대로 잃는 것도 분명합니다.

    • 관리형 서비스의 즉시성
    • 긴 retention과 팀 기능의 편의성
    • 장애 시 벤더에 기대는 심리적 안정감

    그래서 결론은 단순합니다. 메트릭 위주의 소규모~중간 규모 환경이라면 자체 Prometheus는 충분히 매력적입니다. 반면 로그, 트레이스, 장기 보관, 멀티팀 협업이 핵심이면 Grafana Cloud가 여전히 좋은 선택일 수 있습니다. 결국 핵심은 도구 종교가 아니라 ROI와 운영 책임 범위입니다.

    Grafana Cloud 비용 분석 후 자체 Prometheus 전환 결과 대시보드 이미지

    자체 Prometheus 전환 후 Grafana 대시보드와 리소스 사용량을 함께 확인하는 결과 예시입니다.

    9. 정리와 FAQ

    자주 묻는 질문

    • Q. Grafana Cloud를 완전히 버려야 하나요?
      아닙니다. 메트릭만 자체 호스팅하고, 로그나 외부 공유 대시보드는 관리형을 유지하는 혼합형도 충분히 좋습니다.
    • Q. 자체 호스팅 ROI는 언제 좋아지나요?
      청구서 증가 속도보다 VM/스토리지/운영 시간 증가 속도가 느릴 때입니다. 특히 retention이 짧고 운영 범위가 작을수록 유리합니다.
    • Q. 다음 단계는 뭘 보면 좋을까요?
      다음 글에서는 Node Exporter, Alertmanager, 그리고 카디널리티 줄이는 실전 팁을 정리해볼 예정입니다. 이전 글에서 다뤘던 홈랩 스토리지 설계와도 연결해서 보시면 더 이해가 쉬우실 겁니다.

    정리하면 이렇습니다. Grafana Cloud 비용이 부담스럽다고 느껴지는 순간이 오면, 무조건 해지부터 할 필요는 없습니다. 먼저 내 사용량 구조를 보고, 어떤 데이터가 비용을 끌어올리는지 파악한 뒤, 메트릭부터 단계적으로 분리해보세요. 저처럼 한 번 직접 돌려보면, 어떤 환경에서 자체 호스팅이 맞는지 감이 꽤 선명해집니다. 처음엔 헷갈려도, 막상 해보면 생각보다 어렵지 않습니다.

    Grafana Cloud 비용과 자체 호스팅 ROI를 비교한 인포그래픽

    Grafana Cloud와 자체 호스팅 ROI를 한눈에 정리한 비교 인포그래픽 예시입니다.

    참고한 공식 문서

  • [홈랩] Proxmox Grafana 연동: 실시간 시스템 모니터링 대시보드 구축하기

    [홈랩] Proxmox Grafana 연동: 실시간 시스템 모니터링 대시보드 구축하기

    [홈랩] Proxmox Grafana 연동: 실시간 시스템 모니터링 대시보드 구축하기

    홈랩이나 작은 서버실을 굴리다 보면 제일 먼저 드는 생각이 있습니다. “지금 이 서버가 멀쩡한 건가?” 하는 거요. 저도 처음엔 Proxmox VE(프록스목스 가상화 플랫폼) 웹 UI만 열어두고 CPU랑 메모리 그래프만 대충 봤었는데, VM(가상 머신) 몇 대 늘어나고 백업 작업까지 겹치니까 감으로 운영하는 게 한계가 오더라고요. 그래서 정리한 게 바로 Proxmox Grafana 연동입니다. 실시간 모니터링을 붙여두면 장애가 터진 뒤에 보는 게 아니라, 터지기 전에 징후를 읽을 수 있게 되거든요.

    특히 디스크 I/O가 순간적으로 튄다든지, 특정 시간대에 메모리 압박이 몰린다든지, 네트워크 사용량이 평소와 다르게 치솟는다든지 하는 패턴은 대시보드로 봐야 감이 옵니다. 실제로 써보니까 “아, 이 VM 때문에 스토리지가 버벅였구나” 같은 걸 훨씬 빨리 잡게 되더라고요. 여기서 중요한 포인트는, 복잡한 엔터프라이즈 구성을 바로 따라 하기보다 작게 시작해서 계속 확장 가능한 구조로 가는 겁니다.

    Proxmox 호스트, Prometheus, Grafana가 어떤 흐름으로 연결되는지 보여주는 전체 구성 예시입니다.

    왜 Proxmox Grafana 연동이 필요한가요?

    쉽게 말해 Proxmox는 가상화 운영에 강하고, Grafana는 시각화에 강합니다. Proxmox 웹 화면만으로도 기본 상태는 볼 수 있지만, 장기간 추세 확인이나 여러 노드 비교, 경고 기준 잡기에는 조금 아쉬운 부분이 있습니다. 반대로 Grafana는 숫자를 보기 좋게 정리해 주고, 한 화면에 여러 지표를 모아서 보여주기 좋습니다.

    제가 직접 해보니 둘을 묶었을 때 가장 편했던 점은 아래 세 가지였습니다.

    • 실시간 모니터링이 가능해서 순간 부하를 놓치지 않습니다.
    • 대시보드 구축이 쉬워서 CPU, 메모리, 디스크, 네트워크를 한 번에 봅니다.
    • 시스템 성능 추세를 쌓아두면 증설 타이밍을 판단하기 편합니다.

    구성 개념 먼저 잡고 가겠습니다

    저도 처음엔 이게 뭔가 싶었는데, 구조를 한 번만 이해하면 생각보다 단순합니다.

    구성 요소 역할 쉽게 말하면
    Proxmox VE 가상화 호스트 운영 VM과 LXC(리눅스 컨테이너)를 돌리는 본체
    node_exporter 시스템 메트릭 노출 CPU, 메모리, 디스크 같은 숫자를 밖으로 보여주는 창구
    Prometheus 메트릭 수집 및 저장 정해진 주기로 숫자를 긁어와 쌓는 수집기
    Grafana 시각화 쌓인 숫자를 대시보드로 예쁘고 실용적으로 보여주는 도구

    이번 글에서는 가장 무난하게 많이 쓰는 흐름인 Proxmox 호스트 + node_exporter + Prometheus + Grafana 기준으로 설명드릴게요. 이 방식은 홈랩에서도 부담이 적고, 나중에 알람(Alerting)이나 추가 노드 확장도 비교적 자연스럽습니다.

    구축 전 체크할 것들

    설치 들어가기 전에 몇 가지만 확인해 두면 삽질을 많이 줄일 수 있습니다 ㅎㅎ

    1. Proxmox 호스트가 정상 동작 중인지 확인합니다.
    2. Prometheus와 Grafana를 올릴 별도 VM 또는 같은 관리용 서버를 준비합니다.
    3. 방화벽에서 Prometheus 수집 포트와 Grafana 접속 포트를 확인합니다.
    4. 시간 동기화가 맞는지 봅니다. 시간 틀어지면 그래프가 이상하게 보일 수 있거든요.

    참고로 저는 관리용 VM을 따로 두는 편입니다. Proxmox 호스트에 이것저것 다 올릴 수도 있지만, 나중에 분리하고 싶어질 가능성이 높더라고요. 특히 테스트 환경에서는 더 그렇습니다.

    실전 구현 1: Proxmox 호스트에 node_exporter 설치

    먼저 Proxmox 호스트의 시스템 지표를 외부에서 읽게 만들어봅시다. 여기서 사용하는 node_exporter는 Prometheus 생태계에서 가장 널리 쓰이는 시스템 메트릭 수집용 에이전트입니다.

    Debian 계열 기준으로 아래처럼 진행하면 됩니다. Proxmox VE도 Debian 기반이라 흐름은 비슷합니다.

    apt update
    apt install -y prometheus-node-exporter
    systemctl enable --now prometheus-node-exporter
    systemctl status prometheus-node-exporter

    설치가 끝나면 기본적으로 9100 포트에서 메트릭을 노출하게 됩니다. 여기서 중요한 건, 외부에 무작정 열지 말고 관리망에서만 접근 가능하게 두는 겁니다.

    ss -tulpen | grep 9100
    curl http://127.0.0.1:9100/metrics | head

    위 명령에서 숫자가 쭉 나오면 정상입니다. 처음 보면 좀 당황스럽습니다. 저도 “이걸 사람이 어떻게 읽지?” 싶었는데, 사람이 읽는 용도가 아니라 Prometheus가 읽는 형식이라고 생각하시면 됩니다.

    Proxmox Grafana 연동을 위한 node_exporter 메트릭 확인 화면

    node_exporter가 정상적으로 실행되고 메트릭이 노출되는지 확인하는 예시 화면입니다.

    실전 구현 2: Prometheus 설정으로 Proxmox 메트릭 수집

    이제 Prometheus가 Proxmox 호스트의 메트릭을 주기적으로 가져가도록 설정합니다. Prometheus 설정 파일은 보통 prometheus.yml입니다.

    global:
      scrape_interval: 15s
      evaluation_interval: 15s
    
    scrape_configs:
      - job_name: "proxmox-node"
        static_configs:
          - targets:
              - "192.168.0.10:9100"

    여기서 192.168.0.10은 Proxmox 호스트 IP로 바꿔주시면 됩니다. 여러 노드를 운영 중이면 targets에 계속 추가하면 되고요.

    promtool check config /etc/prometheus/prometheus.yml
    systemctl restart prometheus
    systemctl status prometheus

    promtool 검사를 먼저 하는 습관을 들이시면 좋습니다. YAML(야믈, 들여쓰기 기반 설정 형식)은 공백 하나 때문에도 실패하거든요. 저는 여기서 띄어쓰기 때문에 10분 넘게 헤맨 적 있습니다.

    Prometheus 웹 UI에 들어가서 타깃 상태를 확인해 보세요. 상태가 UP으로 보이면 수집이 정상입니다.

    실전 구현 3: Grafana 데이터 소스 연결과 대시보드 구축

    이제부터가 진짜 재미있는 구간입니다. 데이터를 쌓는 것까지 끝났다면, Grafana에서 읽어와 보기 좋은 대시보드로 만들면 됩니다. Proxmox Grafana 연동의 체감 포인트가 여기서 확 옵니다.

    1. Grafana에 로그인합니다.
    2. Data Sources에서 Prometheus를 추가합니다.
    3. Prometheus URL을 입력합니다.
    4. Save & Test로 연결 상태를 확인합니다.
    5. 새 Dashboard를 만들고 패널을 추가합니다.

    Prometheus URL 예시는 보통 아래처럼 넣습니다.

    http://192.168.0.20:9090

    패널에서 바로 써먹기 좋은 기본 쿼리 예시는 이런 식입니다.

    100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
    (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
    rate(node_network_receive_bytes_total[5m])
    rate(node_disk_read_bytes_total[5m])

    첫 번째는 CPU 사용률, 두 번째는 메모리 사용률, 세 번째와 네 번째는 네트워크 및 디스크 처리량 확인에 많이 씁니다. 꼭 외울 필요는 없습니다. 일단 하나씩 붙여보면서 어떤 값이 나오는지 보는 게 더 빨라요.

    Proxmox Grafana 연동 설정과 대시보드 구축 화면

    Grafana에서 Prometheus를 데이터 소스로 등록하고 기본 패널을 구성하는 예시입니다.

    추천 대시보드 구성

    • 상단: 전체 노드 상태 요약, 업타임, 현재 부하
    • 중단: CPU, 메모리, Load Average(로드 애버리지, 시스템 평균 부하)
    • 하단: 디스크 읽기/쓰기, 네트워크 송수신, 파일시스템 사용률

    혹시 여기서 “VM별로도 더 자세히 보고 싶은데요?” 싶으실 수 있습니다. 그럴 땐 수집 대상을 더 세분화하거나, 별도 exporter(익스포터, 메트릭 노출 도구)를 추가하는 방식으로 확장할 수 있어요. 다만 처음부터 욕심내면 오히려 구조가 꼬이기 쉬워서, 저는 호스트 레벨 모니터링부터 안정화하는 걸 추천드립니다.

    대시보드 설계 팁: 숫자보다 패턴이 중요합니다

    실제로 써보니까 예쁜 대시보드보다 중요한 건 문제 패턴이 바로 보이게 만드는 것이었습니다. 예를 들어 CPU 패널만 크게 놓는 것보다, 같은 시간축에 디스크 I/O와 메모리 사용량을 같이 두는 게 원인 추적에 훨씬 유리합니다.

    패널 보면 좋은 이유 주의할 점
    CPU Usage 부하 급증 구간 확인 짧은 스파이크에만 과민 반응하지 않기
    Memory Usage 누수나 캐시 압박 확인 리눅스 캐시 사용을 오해하지 않기
    Disk I/O 스토리지 병목 파악 백업 시간대와 함께 보기
    Network Throughput 백업, 마이그레이션, 다운로드 패턴 확인 단발성 피크와 지속 부하를 구분하기

    여기서 중요한 포인트! 시스템 성능은 단일 수치보다 상관관계로 봐야 합니다. CPU가 높은데 실제 원인은 디스크 대기 때문인 경우도 있고, 네트워크가 치솟아서 백업이 오래 걸리는 경우도 있거든요.

    ⚠️ 제가 겪었던 문제와 트러블슈팅

    이 파트는 좀 현실적으로 적어보겠습니다. 저도 처음엔 설정 몇 줄 넣으면 끝날 줄 알았는데, 은근히 자잘한 문제를 많이 만났습니다.

    1. Prometheus 타깃이 DOWN으로 보일 때

    • node_exporter 서비스가 실제로 떠 있는지 확인합니다.
    • 포트 접근이 방화벽에서 막히지 않았는지 봅니다.
    • Prometheus 설정의 IP와 포트가 맞는지 다시 확인합니다.
    systemctl status prometheus-node-exporter
    curl http://192.168.0.10:9100/metrics
    journalctl -u prometheus -n 50

    2. 그래프는 나오는데 값이 이상할 때

    이건 대개 쿼리나 단위 해석 문제였습니다. 예를 들어 바이트(bytes)와 비트(bits)를 혼동하면 네트워크 그래프가 엉뚱하게 보이더라고요. 또 메모리 사용량은 캐시 영역 때문에 숫자만 보고 “메모리 꽉 찼네”라고 오해하기 쉽습니다.

    3. 대시보드가 너무 복잡해질 때

    처음엔 이것도 넣고 저것도 넣고 싶어집니다. 저도 그랬고요. 근데 결국 자주 보는 패널만 남더라고요. 운영 화면은 한눈에 이해되는 것이 제일 중요합니다. 디테일한 패널은 별도 탭으로 분리하는 게 좋았습니다.

    4. 시간축이 어긋나 보일 때

    서버 시간 동기화 문제를 꼭 확인하세요. 모니터링에서 시간 꼬이면 진짜 골치 아픕니다. 그래프가 안 맞아 보이는 순간 신뢰도가 확 떨어지거든요.

    Proxmox Grafana 연동 상태를 검증하는 Prometheus 모니터링 화면

    Prometheus에서 수집 대상 상태를 점검하며 문제를 찾는 장면을 표현한 이미지입니다.

    검증: 제대로 붙었는지 어떻게 확인할까요?

    구축이 끝났다면 아래 순서로 검증해 보시면 됩니다.

    1. Prometheus Targets 화면에서 Proxmox 노드가 UP인지 확인합니다.
    2. Grafana 패널에서 최근 15분 데이터가 정상적으로 쌓이는지 봅니다.
    3. 테스트로 부하를 조금 주고 그래프 변화가 바로 반영되는지 확인합니다.

    예를 들어 Proxmox 호스트에서 패키지 업데이트나 파일 복사 작업을 수행해 보면 CPU, 디스크, 네트워크 그래프가 움직이는 걸 바로 볼 수 있습니다. 드디어 됐다! 싶은 순간이 여기입니다. 이 맛에 모니터링 붙이는 거죠.

    apt update
    dd if=/dev/zero of=/tmp/io-test.bin bs=1M count=256 oflag=direct
    rm -f /tmp/io-test.bin

    테스트 명령은 운영 환경 상황을 보고 조심해서 사용하셔야 합니다. 특히 디스크 테스트는 스토리지 성격에 따라 부담이 될 수 있으니 무리하지 않는 선에서 확인하세요.

    정리: 제가 추천하는 최소 구성

    처음 시작하신다면 아래 정도면 충분합니다.

    • Proxmox 호스트마다 node_exporter 설치
    • 별도 관리 VM에 Prometheus 설치
    • Grafana에서 호스트별 대시보드 1개, 전체 요약 대시보드 1개 구성
    • CPU, 메모리, 디스크 I/O, 네트워크만 먼저 안정화

    이 구성이 좋은 이유는 단순합니다. 운영이 쉽고, 나중에 확장도 자연스럽습니다. 실제로 Proxmox Grafana 연동을 해두면 장애 대응 속도가 꽤 달라집니다. 문제가 생긴 뒤 로그를 뒤지는 시간이 줄고, 평소 패턴을 알아야 이상 징후도 빨리 눈에 들어오거든요.

    Proxmox Grafana 연동 완료 후 실시간 시스템 성능 대시보드

    CPU, 메모리, 디스크, 네트워크 지표가 한눈에 보이는 최종 대시보드 요약 이미지입니다.

    마무리: 실시간 모니터링은 사치가 아니라 기본입니다

    예전엔 저도 “작은 홈랩인데 굳이 여기까지 해야 하나?” 싶었습니다. 근데 한 번 붙여보면 생각이 바뀝니다. 실시간 모니터링은 큰 환경에서만 필요한 게 아니라, 오히려 혼자 운영하는 작은 환경일수록 더 중요하더라고요. 사람이 적을수록 대시보드가 대신 봐줘야 하니까요.

    이번 글에서는 가장 보편적인 방식으로 Proxmox Grafana 연동 흐름을 정리해봤습니다. 다음 단계로는 알람 조건을 붙이거나, 여러 Proxmox 노드를 비교하는 대시보드까지 확장해 보시면 좋습니다. 이전 글에서 다룬 백업 전략과 같이 묶어보면 운영 안정성이 훨씬 좋아집니다. 다음 글에서는 Alerting(알러팅, 임계치 기반 경고) 쪽도 따로 다뤄볼 예정입니다.

    혹시 지금 Proxmox는 잘 돌아가는데, 가끔씩 이유 없이 느려지는 순간이 있으신가요? 그럴 때야말로 대시보드가 진짜 힘을 발휘합니다. 저도 처음엔 헷갈렸는데, 한번 구축해 두니까 운영이 훨씬 편해졌습니다. 이거 진짜 편하더라고요.

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

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

    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. 옵저버빌리티 전환의 성공 기준은 뭔가요?

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

  • [Proxmox] Proxmox API 활용, Grafana 연동을 통한 자원 사용량 모니터링 및 자동화 사례

    [Proxmox] Proxmox API 활용, Grafana 연동을 통한 자원 사용량 모니터링 및 자동화 사례

    [인프라] Proxmox API Grafana 연동으로 자원 사용량 모니터링과 자동화 사례

    홈랩이나 소규모 가상화 환경을 굴리다 보면, 처음에는 Proxmox VE(프록스목스 가상화 환경) 웹 UI만 봐도 충분하다고 느끼실 수 있습니다. 저도 그랬거든요. 그런데 VM이 몇 대만 넘어가도 CPU, Memory(메모리), Storage(스토리지) 사용량이 순간적으로 튀는 구간이 보이고, 그때마다 사람이 직접 들어가 확인하는 방식은 금방 한계가 오더라고요. 그래서 이번 글에서는 Proxmox API Grafana 조합으로 자원 사용량을 한눈에 보고, 특정 조건에서는 자동화까지 연결한 실제 운영 패턴을 정리해보겠습니다. Proxmox 모니터링과 API 자동화, Grafana 연동이 왜 같이 가야 하는지, 제가 직접 해보면서 느낀 삽질 포인트까지 솔직하게 적어보겠습니다.

    특히 이런 분들께 잘 맞습니다. VM 수가 늘면서 자원 사용량을 장기적으로 보고 싶으신 분, 장애 직전의 징후를 미리 잡고 싶으신 분, 그리고 반복 확인 작업을 자동화하고 싶으신 분이요. 여기서 중요한 포인트! 단순히 대시보드만 예쁘게 만드는 게 목적이 아니라, 운영 판단 속도를 올리는 것이 핵심입니다.

    Proxmox API Grafana 연동 전체 흐름을 보여주는 아키텍처 예시입니다. Proxmox 노드, 메트릭 수집 스크립트, 시각화 계층의 관계를 한눈에 볼 수 있게 배치하면 이해가 훨씬 쉬워집니다.

    왜 Proxmox API Grafana 구성이 중요한가

    쉽게 말해 Proxmox API는 현재 상태를 꺼내오는 창구이고, Grafana는 그 상태를 사람이 판단하기 좋은 형태로 보여주는 대시보드입니다. 둘을 따로 보면 평범한데, 같이 묶으면 운영 품질이 꽤 달라집니다.

    예를 들어 웹 UI에서는 지금 CPU가 높은지 낮은지 바로 볼 수는 있어도, 지난 일주일 동안 특정 VM이 언제부터 메모리를 먹기 시작했는지, 백업 시간대와 I/O 부하가 겹쳤는지 같은 맥락은 금방 흐려집니다. 실제로 써보니까, 이 부분이 사람이 체감하는 운영 난이도를 크게 갈라놓더라고요.

    • Proxmox API: 노드, VM, 컨테이너(CT), 스토리지 상태를 JSON 형태로 조회
    • Grafana: 시계열 그래프, 표, 상태 패널로 이상 징후 시각화
    • 자동화: 임계치 초과 시 알림 또는 후속 작업 실행

    저는 초반에 “그냥 필요한 순간에 UI 들어가서 보면 되지 않을까?”라고 생각했었는데요. 막상 밤에 부하가 튀고, 다음 날 와서 원인을 보려니 이미 지나간 데이터는 감으로만 추적하게 되더라고요. 그때부터 API 기반 수집을 붙였습니다. 드디어 됐다 싶은 순간이 있었던 게, 장애가 나기 전에 패턴이 보이기 시작했다는 점이었습니다.

    핵심 개념 정리: API 자동화와 Proxmox 모니터링

    Proxmox API는 무엇을 주는가

    Proxmox VE는 REST API(레스트 API, HTTP 기반 관리 인터페이스)를 제공합니다. 이 API로 노드 목록, VM 상태, CPU 사용량, 메모리 점유, 디스크 상태 같은 정보를 조회할 수 있습니다. 인증은 보통 API Token(토큰 인증)이나 세션 기반으로 처리합니다.

    여기서 주의하실 점은, API가 만능은 아니라는 겁니다. 현재값(current) 조회에는 아주 편하지만, 장기 보관과 비교 분석은 별도 저장 계층이 있어야 합니다. 그래서 Grafana를 붙일 때도 대개는 중간에 메트릭 저장소나 수집 스크립트를 둡니다.

    Grafana는 어디서 빛나는가

    Grafana는 단순 그래프 툴이 아니라, 운영자가 “그래서 지금 뭘 해야 하지?”를 판단하게 해주는 시각화 도구에 가깝습니다. CPU 평균, 메모리 사용률, VM별 트렌드, 노드별 비교, 이상치 탐지에 강하거든요.

    구성 요소 역할 운영 포인트
    Proxmox API 실시간 상태 조회 인증과 요청 빈도 관리가 중요
    수집 스크립트 API 응답을 메트릭 형태로 변환 실패 시 재시도와 로그 필요
    Prometheus 시계열 메트릭 저장 스크랩 주기와 보존 기간 설계
    Grafana 대시보드/알림 운영자 시점 패널 구성 필요

    혹시 이런 경험 있으신가요? 숫자는 많은데, 막상 어떤 VM이 문제인지 바로 안 보이는 상황이요. 저는 딱 그랬습니다. 그래서 패널을 예쁘게 만드는 것보다, 노드 단위와 VM 단위를 분리해서 보는 구조가 더 중요하다는 걸 뒤늦게 배웠습니다.

    실전 구현 1: Proxmox API 토큰과 수집 흐름 만들기

    제가 실제로 안정적으로 썼던 방식은 이렇습니다. Proxmox API에서 값을 읽고, Python(파이썬) 스크립트로 필요한 필드만 정리한 뒤, Prometheus exporter(프로메테우스 익스포터, 메트릭 노출기) 형태로 내보내고, Grafana에서 이를 시각화하는 구조입니다. Grafana가 직접 API를 두드리는 방식도 가능은 하지만, 운영해보니 중간 계층을 두는 편이 훨씬 관리가 편하더라고요.

    1. Proxmox에서 읽기 전용 API Token 생성
    2. 수집 대상 노드와 VM 범위 정의
    3. Python 스크립트로 API 호출 및 메트릭 변환
    4. Prometheus가 주기적으로 수집
    5. Grafana 대시보드와 알림 정책 구성

    1. API 토큰 준비

    실서비스든 홈랩이든, 자동화에는 계정 분리가 기본입니다. 관리자 계정을 그대로 물리는 건 추천드리지 않습니다. 최소 권한 원칙(Principle of Least Privilege, 최소 권한 원칙)으로 읽기 전용 토큰을 따로 만드시는 게 좋습니다.

    export PVE_HOST="https://proxmox.example.local:8006"
    export PVE_TOKEN_ID="monitor@pve!grafana"
    export PVE_TOKEN_SECRET="YOUR_TOKEN_SECRET"
    

    환경 변수로 분리해두면 스크립트 수정 없이 운영하기 편합니다. 저는 처음에 토큰 문자열을 코드 안에 박아뒀다가, 나중에 회전(rotation)할 때 꽤 귀찮았거든요.

    2. API 확인

    먼저 가장 단순한 조회부터 붙여보면 감이 옵니다.

    curl -k -H "Authorization: PVEAPIToken=${PVE_TOKEN_ID}=${PVE_TOKEN_SECRET}" \
      "${PVE_HOST}/api2/json/nodes"
    

    응답은 JSON 형태로 오고, 여기서 노드 이름을 먼저 확인할 수 있습니다. 그다음 특정 노드의 상태를 조회합니다.

    NODE="pve01"
    curl -k -H "Authorization: PVEAPIToken=${PVE_TOKEN_ID}=${PVE_TOKEN_SECRET}" \
      "${PVE_HOST}/api2/json/nodes/${NODE}/status"
    

    이 단계에서 API 응답 구조를 손으로 한 번 읽어보시는 걸 추천드립니다. 제가 직접 해보니, 어떤 필드를 지표로 쓸지 이때 정리해두면 이후 Grafana 패널 설계가 훨씬 빨라집니다.

    Proxmox API 응답과 메트릭 수집 흐름을 보여주는 Grafana 연동 이미지

    API 응답 JSON에서 CPU, 메모리, 디스크 필드를 골라 메트릭으로 바꾸는 과정을 표현한 이미지 자리입니다. 중간 수집 계층의 역할을 보여주면 실전 흐름 이해에 도움이 됩니다.

    실전 구현 2: Python으로 메트릭 변환하고 Grafana 연동하기

    여기서는 예시로 간단한 Python 스크립트를 사용하겠습니다. 핵심은 Proxmox API 응답을 가져와서 Prometheus가 읽기 좋은 텍스트 포맷으로 내보내는 겁니다.

    import os
    import requests
    from flask import Flask, Response
    
    app = Flask(__name__)
    
    PVE_HOST = os.environ["PVE_HOST"]
    PVE_TOKEN_ID = os.environ["PVE_TOKEN_ID"]
    PVE_TOKEN_SECRET = os.environ["PVE_TOKEN_SECRET"]
    VERIFY_TLS = False
    
    
    def pve_get(path: str):
        headers = {
            "Authorization": f"PVEAPIToken={PVE_TOKEN_ID}={PVE_TOKEN_SECRET}"
        }
        r = requests.get(f"{PVE_HOST}{path}", headers=headers, verify=VERIFY_TLS, timeout=10)
        r.raise_for_status()
        return r.json()["data"]
    
    
    @app.route("/metrics")
    def metrics():
        lines = []
        nodes = pve_get("/api2/json/nodes")
    
        for node in nodes:
            node_name = node["node"]
            status = pve_get(f"/api2/json/nodes/{node_name}/status")
    
            cpu = status.get("cpu", 0)
            maxmem = status.get("memory", {}).get("total", 0) if isinstance(status.get("memory"), dict) else 0
            usedmem = status.get("memory", {}).get("used", 0) if isinstance(status.get("memory"), dict) else 0
    
            lines.append(f'proxmox_node_cpu_ratio{{node="{node_name}"}} {cpu}')
            lines.append(f'proxmox_node_memory_used_bytes{{node="{node_name}"}} {usedmem}')
            lines.append(f'proxmox_node_memory_total_bytes{{node="{node_name}"}} {maxmem}')
    
        body = "\n".join(lines) + "\n"
        return Response(body, mimetype="text/plain; version=0.0.4")
    
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=9108)
    

    여기서 한 가지 말씀드리면, 실제 API 응답 필드 구조는 환경에 따라 확인이 필요합니다. 그래서 처음부터 모든 리소스를 다 넣기보다, CPU와 메모리처럼 운영 판단에 바로 쓰이는 값부터 시작하는 편이 좋습니다. 저도 처음엔 욕심내서 디스크, 네트워크, VM 상태, 백업 작업까지 한 번에 넣으려다가 오히려 디버깅 시간이 길어졌습니다.

    Prometheus 스크랩 설정

    scrape_configs:
      - job_name: "proxmox-api-exporter"
        metrics_path: /metrics
        static_configs:
          - targets:
              - "proxmox-exporter.local:9108"
    

    이제 Grafana에서는 Prometheus 데이터 소스를 연결하고 패널을 만듭니다. 예를 들면 이런 쿼리들이 기본 뼈대가 됩니다.

    proxmox_node_cpu_ratio * 100
    
    (proxmox_node_memory_used_bytes / proxmox_node_memory_total_bytes) * 100
    

    Grafana 연동에서 중요한 건 패널 개수보다 뷰의 목적입니다. 저는 보통 아래처럼 나눕니다.

    • 상단: 노드별 CPU, 메모리 전체 상태
    • 중단: VM별 Top N 사용량
    • 하단: 지난 24시간 변화량과 이상 구간

    이 구성이 생각보다 편합니다. 문제를 위에서 아래로 좁혀 들어가기 좋거든요.

    실전 구현 3: API 자동화로 반복 작업 줄이기

    이제 대시보드가 보이기 시작하면, 다음 단계는 자동화입니다. 저는 처음에 알림만 붙였다가, 나중에는 특정 조건에서 후속 작업을 자동으로 실행하는 구조까지 확장했습니다. 여기서 말하는 자동화는 무조건 VM을 강제로 끄는 위험한 방식이 아니라, 안전한 선에서 운영자 개입을 줄이는 보조 자동화입니다.

    예를 들면 이런 식입니다.

    1. 특정 노드 메모리 사용률이 일정 시간 이상 높게 유지됨
    2. Grafana Alerting(알림) 또는 별도 스크립트가 Webhook(웹훅)을 호출
    3. Webhook 수신 스크립트가 Slack, 메일, 또는 내부 운영 채널로 통보
    4. 필요 시 사전 정의된 Ansible(앤서블, 자동화 도구) 작업 실행

    저는 여기서 “자동 복구”라는 말을 쉽게 쓰지 않습니다. 자동화는 편하지만, 잘못 걸면 장애를 키우거든요. 대신 알림 + 안전한 후속 조치 구조가 현실적이었습니다.

    import requests
    
    THRESHOLD = 0.90
    
    
    def notify_if_high(node_name, memory_ratio):
        if memory_ratio >= THRESHOLD:
            requests.post(
                "https://hooks.example.local/proxmox-alert",
                json={
                    "node": node_name,
                    "metric": "memory",
                    "ratio": memory_ratio,
                    "message": f"{node_name} memory usage is high"
                },
                timeout=5,
            )
    

    작게 시작하시는 걸 추천드립니다. 예를 들면 “임계치 초과 시 알림”까지만 먼저 붙여도 운영 피로도가 꽤 줄어듭니다. 그다음에 스냅샷 정리, 백업 전 상태 점검, 테스트 VM 정리 같은 보조 자동화를 단계적으로 넣는 게 안전합니다.

    Proxmox 모니터링과 Grafana 연동 결과를 보여주는 운영 대시보드 이미지

    노드 CPU, 메모리 추이 그래프와 임계치 초과 알림 흐름을 함께 보여주는 이미지 자리입니다. 결과가 머릿속에 바로 그려지게 만드는 용도로 좋습니다.

    ⚠️ 제가 겪었던 문제들: 인증, TLS, 지표 해석

    여기 구간은 정말 중요합니다. 문서만 보면 금방 될 것 같았는데, 실제로는 여기서 삽질을 좀 했습니다 ㅎㅎ

    1. API 인증은 되는데 일부 엔드포인트가 비어 보이는 문제

    원인은 대부분 권한 범위였습니다. 토큰이 살아 있어도 읽기 권한이 필요한 경로에 충분히 부여되지 않으면 응답이 제한적으로 보일 수 있습니다. 관리자 토큰으로 대충 해결하기보다, 어떤 리소스를 읽어야 하는지 먼저 정리하고 권한을 맞추시는 게 좋습니다.

    2. 사설 인증서(Private CA) 때문에 요청 실패

    홈랩에서는 TLS(전송 계층 보안) 인증서를 자체 서명으로 쓰는 경우가 많죠. 저도 처음엔 요청마다 인증서 검증 오류가 났습니다. 개발 단계에서만 검증을 끄고, 운영 단계에서는 신뢰할 수 있는 CA를 배포하는 쪽이 맞습니다. 검증 비활성화는 임시 조치라고 생각하셔야 합니다.

    3. CPU 비율과 메모리 절대값을 한 패널에 섞어놓은 실수

    이거 진짜 헷갈리더라고요. 초반엔 한 패널에 다 넣었다가 그래프 해석이 너무 어려웠습니다. 비율(%)과 절대값(Bytes)은 분리해서 보는 게 맞습니다. 운영자는 예쁜 그래프보다 빠른 판단이 중요하거든요.

    4. 스크랩 주기를 너무 짧게 잡은 문제

    수집 주기를 과하게 짧게 잡으면 API 요청 수만 늘고, 얻는 실익은 크지 않을 수 있습니다. 특히 홈랩처럼 자원이 넉넉하지 않은 환경에서는 더 그렇습니다. 저는 처음엔 촘촘하게 잡아야 정확할 줄 알았는데, 실제로는 운영 목적에 맞는 간격이 더 중요했습니다.

    • 실시간 장애 대응이 목적이면 짧은 주기
    • 용량 계획(capacity planning, 용량 계획)이 목적이면 중간 주기
    • 장기 추세 분석이 목적이면 보존 정책이 더 중요

    검증: 대시보드에서 무엇이 보이면 성공인가

    모니터링은 붙였다고 끝이 아닙니다. 검증 기준이 있어야 합니다. 제가 보는 기준은 아래와 같습니다.

    1. 노드별 CPU, 메모리 사용률이 시간 흐름으로 안정적으로 보이는가
    2. 특정 VM의 급격한 사용량 증가가 구분되는가
    3. 백업, 배치 작업, 업데이트 시간대와 부하 상관관계가 보이는가
    4. 임계치 초과 시 알림이 중복 없이 적절히 오는가

    이 정도만 확보돼도 Proxmox 모니터링 체계가 운영에 실제 도움이 되기 시작합니다. 숫자를 모으는 것과 운영에 쓰는 건 다르거든요. 저는 Grafana에서 하루 뷰, 7일 뷰, 30일 뷰를 나눠두니 체감이 확 달랐습니다. 하루 뷰는 장애 분석용, 7일 뷰는 패턴 확인용, 30일 뷰는 증설 판단용으로 쓰기 좋았습니다.

    그리고 의외로 유용했던 게 표(Table) 패널입니다. Top N VM 목록을 표로 뽑아두면, 그래프보다 바로 눈에 들어오는 경우가 많습니다. 특히 야간에 급한 상황에서는요.

    Proxmox API Grafana 기반 자원 사용량 시각화 결과 이미지

    Grafana에서 CPU, 메모리 추이를 시각화하고 VM별 Top N 표를 함께 보여주는 결과 예시 이미지 자리입니다. 모니터링 완성 상태를 전달하기 좋습니다.

    정리: 제가 다시 구성한다면 이렇게 하겠습니다

    지금 다시 처음부터 구성한다면, 저는 이렇게 갑니다.

    • 1단계: Proxmox API로 노드/VM 기본 지표만 수집
    • 2단계: Prometheus에 저장하고 Grafana에서 노드/VM 대시보드 분리
    • 3단계: 알림 추가
    • 4단계: 안전한 범위의 API 자동화 연결

    중요한 건 처음부터 모든 걸 다 하려 하지 않는 겁니다. 저도 처음엔 “이왕 하는 김에 완벽하게” 갔다가 시간이 꽤 들었어요. 그런데 운영은 결국 지속 가능해야 하더라고요. 작게 시작해서 점진적으로 확장하는 쪽이 훨씬 오래 갑니다.

    이번 글의 핵심을 짧게 정리하면 이렇습니다. Proxmox API Grafana 조합은 단순 시각화 도구가 아니라, 운영 판단 체계를 만드는 기반입니다. API 자동화는 반복 작업을 줄여주고, Grafana 연동은 문제를 더 빨리 보게 해줍니다. 둘이 합쳐질 때 가치가 커집니다.

    다음 글에서는 Proxmox 백업 작업과 알림 흐름을 더 세밀하게 묶는 방법, 그리고 장기 보존 지표를 기준으로 증설 시점을 판단하는 방법도 다뤄볼 예정입니다. 이전 글에서 홈랩 네트워크 분리와 스토리지 구성 이야기를 보셨다면, 이번 구성과 같이 연결해서 보시면 훨씬 이해가 잘 되실 겁니다.

    구성 요소, 장점, 주의사항, 자동화 확장 단계를 한 장으로 요약하는 인포그래픽 자리입니다. 글 마무리 직전에 넣으면 복습용으로 좋습니다.

    자주 묻는 질문

    Grafana가 Proxmox API를 직접 읽어야 하나요?

    반드시 그럴 필요는 없습니다. 제가 운영해보니 중간 수집 계층을 두는 편이 안정적이었습니다. API 응답을 바로 시각화하는 것보다 메트릭 구조를 정리한 뒤 보여주는 쪽이 관리가 쉽습니다.

    API 자동화는 어디까지 붙이는 게 좋을까요?

    처음에는 알림과 로그 수집 정도가 적당합니다. 운영 흐름이 충분히 검증된 뒤에 후속 작업 자동화를 넣는 게 안전합니다.

    Proxmox 모니터링에서 가장 먼저 볼 지표는 무엇인가요?

    노드 CPU, 메모리 사용률, 그리고 VM별 상위 사용량 목록부터 시작하시면 됩니다. 이 세 가지가 문제 파악 속도를 가장 많이 올려줍니다.

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

  • [k8s] 쿠버네티스 모니터링: Prometheus & Grafana 구축 및 대시보드 활용 가이드

    [k8s] 쿠버네티스 모니터링: Prometheus & Grafana 구축 및 대시보드 활용 가이드

    🚀 쿠버네티스 모니터링, 왜 중요할까요?

    안녕하세요, 13년차의 서버실 주인장입니다. 오늘은 쿠버네티스 모니터링의 핵심이라고 할 수 있는 Prometheus(프로메테우스)와 Grafana(그라파나) 구축 경험을 공유해볼까 합니다. 쿠버네티스 환경을 운영하다 보면 ‘도대체 내 파드는 잘 돌고 있나?’, ‘CPU 사용량이 왜 이렇게 높지?’, ‘메모리 누수가 생긴 건 아닐까?’ 같은 고민을 하게 되죠.

    저도 처음 쿠버네티스를 도입했을 때, 여러 파드들이 여기저기서 돌아다니는데 이걸 어떻게 한눈에 볼 수 있을까 막막했어요. 로그를 일일이 뒤져보는 것도 한계가 있고요. 그때 제 눈을 번쩍 뜨이게 한 것이 바로 Prometheus와 Grafana 조합이었습니다. 이 두 가지 도구 덕분에 제 홈랩의 쿠버네티스 클러스터는 24시간 감시 체제를 갖추게 되었고, 문제가 생기면 빠르게 파악하고 조치할 수 있게 됐죠. 마치 제 서버실에 똑똑한 비서 한 명을 들인 기분이랄까요?

    이번 글에서는 이 강력한 모니터링 스택을 어떻게 구축하고, 어떤 대시보드를 활용하면 좋을지 제 경험을 녹여서 자세히 알려드리겠습니다. 삽질했던 부분들도 솔직하게 공유할 테니, 여러분은 저처럼 헤매지 않으시길 바랍니다! 자, 그럼 시작해볼까요?

    쿠버네티스 환경에서 Prometheus와 Grafana를 이용한 모니터링 시스템의 전체 아키텍처 다이어그램입니다.

    💡 Prometheus와 Grafana, 핵심 개념 파헤치기

    자, 이제 본론으로 들어가서 쿠버네티스 모니터링의 양대 산맥인 Prometheus(프로메테우스)와 Grafana(그라파나)에 대해 좀 더 깊이 있게 알아볼까요? 처음엔 이름도 어렵고, 뭐가 뭔지 헷갈렸는데, 사실 원리만 이해하면 생각보다 간단하더라고요.

    Prometheus (프로메테우스): 지표 수집의 달인

    Prometheus는 오픈 소스 모니터링 시스템으로, 시계열 데이터베이스(Time-series Database, TSDB)를 기반으로 합니다. 쉽게 말해, 시간의 흐름에 따라 변화하는 다양한 지표(Metrics)들을 수집하고 저장하는 데 특화된 도구거든요. 기존의 많은 모니터링 시스템이 에이전트가 데이터를 서버로 밀어 넣는 Push 방식이었다면, Prometheus는 대상으로부터 데이터를 Pull(가져오는) 방식을 사용합니다. 이 방식은 서비스 디스커버리(Service Discovery)와 결합될 때 쿠버네티스 같은 동적인 환경에서 정말 큰 시너지를 내거든요.

    • Metrics (메트릭, 지표 데이터): CPU 사용량, 메모리 사용량, 네트워크 트래픽 등 서버나 애플리케이션의 상태를 나타내는 수치 데이터입니다.
    • Exporters (익스포터): Prometheus가 지표를 가져올 수 있도록 데이터를 노출하는 작은 에이전트예요. 예를 들어, 서버의 OS 지표를 수집하는 Node Exporter나 쿠버네티스 노드/파드의 지표를 수집하는 cAdvisor 같은 것들이죠.
    • Service Discovery (서비스 디스커버리): 쿠버네티스 환경에서는 파드(Pod)가 수시로 생성되고 사라집니다. Prometheus는 이런 변화를 감지해서 자동으로 새로운 모니터링 대상을 찾아냅니다. 정말 편리하더라고요.

    Grafana (그라파나): 시각화의 마법사

    Prometheus가 지표를 열심히 수집하고 저장해놨다면, Grafana는 그 데이터를 멋진 그래프와 대시보드로 시각화해주는 도구입니다. 복잡한 숫자들을 한눈에 알아보기 쉽게 보여주니까, 이상 징후를 빠르게 파악하고 문제 해결에 집중할 수 있게 도와주죠. 처음에는 Grafana UI가 좀 어려웠는데, 몇 번 써보니 이거 진짜 물건이더라고요! 다양한 데이터 소스(Prometheus 외에도 많은 DB를 지원합니다)를 연결해서 대시보드를 만들 수 있고, 커스텀도 자유롭습니다.

    🛠️ 실전! Helm으로 Prometheus & Grafana 배포하기

    이제 이론은 충분히 봤으니, 실제로 쿠버네티스 클러스터에 Prometheus와 Grafana를 배포해보겠습니다. 저는 Helm(헬름)을 이용하는 것을 선호하는데, 복잡한 쿠버네티스 리소스들을 한 번에 쉽게 배포하고 관리할 수 있거든요. 마치 패키지 매니저처럼요!

    사전 준비물

    1. 동작하는 쿠버네티스 클러스터 (저는 홈랩에서 Kubeadm으로 구성한 클러스터를 사용했습니다.)
    2. Helm v3 이상 설치
    3. (선택 사항) PersistentVolume(영구 볼륨)을 위한 StorageClass(스토리지 클래스) 설정 (데이터 유실 방지를 위해 권장합니다)

    Step 1: Helm Repository 추가

    Prometheus와 Grafana를 포함하는 <code>kube-prometheus-stack은 Helm 차트로 제공됩니다. 먼저 Helm 레포지토리를 추가해주세요.

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

    Step 2: Prometheus 스택 배포

    이제 kube-prometheus-stack을 배포할 차례입니다. 이 차트 안에는 Prometheus, Grafana, Alertmanager(알림 관리자), Kube-State-Metrics(쿠버네티스 상태 지표 수집기), Node Exporter(노드 지표 수집기) 등 쿠버네티스 모니터링에 필요한 모든 것이 한 번에 들어있어서 정말 편합니다. 저는 보통 monitoring 네임스페이스에 배포합니다.

    ⚠️ 중요: 프로덕션 환경에서는 values.yaml 파일을 통해 스토리지 클래스, 리소스 제한, 서비스 타입 등을 반드시 커스터마이징해야 합니다. 저는 홈랩이라 기본 설정으로 진행했지만, 여러분은 꼭 신경 써주세요!

    # values.yaml 파일 예시 (간단하게 스토리지 클래스만 지정)
    # my-prometheus-values.yaml
    
    prometheus:
      prometheusSpec:
        storageSpec:
          volumeClaimTemplate:
            spec:
              storageClassName: my-storage-class # 본인의 StorageClass 이름으로 변경
              resources:
                requests:
                  storage: 10Gi
    
    grafana:
      persistence:
        enabled: true
        storageClassName: my-storage-class # 본인의 StorageClass 이름으로 변경
        size: 5Gi
    

    이제 위 values.yaml 파일을 적용하여 배포합니다.

    helm install prometheus prometheus-community/kube-prometheus-stack \
      --namespace monitoring --create-namespace \
      -f my-prometheus-values.yaml # 커스터마이징한 values.yaml 파일 적용

    배포가 완료되면 kubectl get pods -n monitoring 명령어로 파드들이 잘 떠 있는지 확인해보세요. 모든 파드가 Running 상태라면 성공입니다! 🎉

    Step 3: Grafana 접속 및 초기 설정

    Grafana는 기본적으로 ClusterIP 타입의 서비스로 배포됩니다. 외부에서 접속하려면 Ingress(인그레스, 외부 트래픽 진입점)를 설정하거나, 간단하게 포트 포워딩(Port-forwarding)을 이용할 수 있어요. 저는 테스트를 위해 포트 포워딩을 자주 사용합니다.

    kubectl port-forward svc/prometheus-grafana 3000:80 -n monitoring

    이제 웹 브라우저에서 http://localhost:3000으로 접속해보세요. 초기 로그인 정보는 다음과 같습니다.

    • User (사용자): admin
    • Password (비밀번호): prom-operator (또는 kubectl get secret prometheus-grafana -n monitoring -o jsonpath='{.data.admin-password}' | base64 --decode 명령어로 확인)

    로그인 후에는 비밀번호 변경을 요청할 겁니다. 안전하게 변경해주세요!

    Grafana에서 Prometheus 데이터 소스를 추가하는 설정 화면입니다.

    📊 나만의 쿠버네티스 대시보드 만들기 & 활용하기

    Grafana에 접속했다면 이제 Prometheus 데이터를 시각화할 차례예요. kube-prometheus-stack 덕분에 Prometheus 데이터 소스는 이미 설정되어 있을 겁니다. 혹시 없다면, Configuration > Data Sources에서 Prometheus를 추가하고 URL을 http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090 (네임스페이스와 서비스 이름에 따라 다를 수 있음)으로 설정하면 됩니다.

    기본 대시보드 활용하기

    kube-prometheus-stack은 기본적으로 여러 유용한 대시보드들을 Grafana에 자동으로 임포트해줍니다. 왼쪽 메뉴에서 Dashboards > Manage로 이동해보세요. 아마 Kubernetes / Compute Resources, Node Exporter Full 같은 대시보드들을 볼 수 있을 겁니다. 저도 처음엔 이 대시보드들만으로도 충분히 모니터링이 가능해서 정말 편하더라고요.

    Grafana Labs 공유 대시보드 임포트하기

    만약 더 다양한 대시보드를 원한다면, Grafana Labs 웹사이트(https://grafana.com/grafana/dashboards/)에서 다른 사람들이 공유한 대시보드를 임포트할 수 있습니다. 예를 들어, Node Exporter Full 대시보드(ID: 1860)나 Kubernetes Cluster Overview(ID: 12150) 같은 것들이 인기가 많죠.

    1. Grafana 좌측 메뉴에서 + > Import를 클릭합니다.
    2. Import via grafana.com dashboard 칸에 대시보드 ID (예: 1860)를 입력하고 Load를 클릭합니다.
    3. 대시보드 이름, 폴더를 설정하고, Prometheus 데이터 소스를 선택한 후 Import를 클릭합니다.

    짜잔! 멋진 대시보드가 눈앞에 펼쳐질 겁니다. 🤩

    나만의 대시보드 커스터마이징

    기존 대시보드를 활용하는 것도 좋지만, 특정 애플리케이션이나 서비스에 특화된 대시보드 구축은 필수입니다. 저는 주로 복제(Duplicate) 기능을 이용해서 기존 대시보드를 복사한 다음, 필요한 패널(Panel)을 추가하거나 수정하는 방식으로 커스터마이징합니다. PromQL(프로메테우스 쿼리 언어)을 조금만 익히면 원하는 지표를 자유자재로 뽑아낼 수 있거든요.

    Prometheus와 Grafana를 통해 구현된 쿠버네티스 클러스터 모니터링 대시보드 예시입니다.

    ⚠️ 삽질 대잔치! 트러블슈팅 경험담

    인프라 엔지니어의 삶은 삽질의 연속이죠. 저도 Prometheus & Grafana 구축 과정에서 몇 번의 삽질을 경험했어요. 여러분은 이런 문제들을 미리 알고 피하시길 바랍니다.

    1. PersistentVolumeClaim (PVC) Pending 문제

    증상: Prometheus나 Grafana 파드가 Pending 상태에서 벗어나지 못하고, PVC가 Pending으로 남아있을 때입니다.

    원인: 대부분 StorageClass가 없거나, 잘못 지정되었을 때 발생합니다. Prometheus는 데이터를 저장하기 위해 영구 스토리지를 써야 하는데, 이를 위한 StorageClass가 없으면 볼륨을 프로비저닝할 수 없거든요.

    해결: 클러스터에 NFS CSI Driver나 Longhorn 같은 동적 프로비저너를 설치하고, 해당 StorageClass를 values.yaml에 올바르게 지정해주세요. 저는 처음에 이 부분을 놓쳐서 한참 헤맸습니다. 🤦‍♂️

    2. 리소스 부족으로 인한 OOMKilled

    증상: Prometheus 파드가 자꾸 재시작되면서 OOMKilled(Out Of Memory Killed) 오류가 발생합니다.

    원인: Prometheus는 수집하는 지표의 양이 많아질수록 메모리 사용량이 늘어나요. 기본 설정된 리소스 제한(Resource Limits)이 클러스터 규모에 비해 너무 낮을 때 발생하는 거죠.

    해결: values.yaml에서 Prometheus 파드의 resources.requests와 resources.limits를 적절히 늘려주세요. 특히 memory 부분을 여유 있게 설정하는 게 중요합니다. 너무 많이 늘리면 다른 파드에 영향을 줄 수 있으니, 모니터링하면서 점진적으로 조정하는 것을 추천합니다.

    3. Prometheus가 타겟을 찾지 못하는 문제

    증상: Grafana 대시보드에서 데이터가 보이지 않거나, Prometheus UI의 Targets 페이지에서 특정 파드가 DOWN 상태로 표시될 때입니다.

    원인: Prometheus의 서비스 디스커버리 설정이 잘못되었거나, 파드에 올바른 레이블(Label)이 지정되지 않았을 때, 혹은 네트워크 정책(Network Policy) 등으로 인해 Prometheus가 파드의 익스포터에 접근하지 못할 때 발생합니다.

    해결:

    • 해당 파드에 Prometheus가 찾을 수 있는 annotations나 labels가 잘 붙어있는지 확인합니다. (예: prometheus.io/scrape: "true")
    • ServiceMonitor 또는 PodMonitor 리소스가 올바르게 정의되어 있는지 확인합니다.
    • 네트워크 정책이 Prometheus 파드에서 대상 파드로의 트래픽을 허용하는지 검토합니다.

    제가 직접 커스텀 애플리케이션을 모니터링할 때 이 문제로 고생 좀 했어요. 애플리케이션 파드에 어노테이션을 빼먹어서 그랬더라고요. ㅎㅎ

    ✅ 구축 결과 확인 및 다음 단계 제안

    이제 여러분의 쿠버네티스 클러스터는 Prometheus와 Grafana라는 강력한 모니터링 시스템을 갖추게 되었습니다. Grafana 대시보드를 통해 노드의 CPU/메모리 사용량, 파드의 상태, 네트워크 트래픽 등 다양한 지표들을 한눈에 볼 수 있을 겁니다. 문제가 발생하면 즉시 알 수 있고, 미리 예방할 수도 있게 되는 거죠. 정말 뿌듯하지 않나요? 🎉

    저도 처음 이 대시보드를 보면서 ‘드디어 됐다!’ 싶었던 기억이 생생하네요. 덕분에 제 홈랩 클러스터가 훨씬 더 안정적으로 운영되고 있습니다.

    다음 단계로 나아가기

    여기서 멈추지 마세요! 쿠버네티스 모니터링은 계속 발전해야 합니다. 몇 가지 다음 단계를 제안해봅니다.

    • Alertmanager(알림 관리자) 설정: Prometheus가 수집한 지표를 기반으로 알림(Alert)을 생성하고, 이를 Slack, 이메일, PagerDuty 등으로 전송하도록 설정해보세요. 저는 슬랙으로 알림을 받는데, 긴급 상황 발생 시 정말 유용합니다.
    • Custom Exporter 개발: 여러분의 특정 애플리케이션에서만 나오는 커스텀 지표를 수집하고 싶다면, 직접 익스포터를 개발해보는 것도 좋은 경험입니다. Python이나 Go 언어로 쉽게 만들 수 있어요.
    • 장기 지표 저장 (Long-term Storage): Prometheus는 기본적으로 로컬 스토리지를 써요. 장기간 지표를 보관하고 싶다면 Thanos(타노스)나 Cortex(코텍스) 같은 솔루션을 연동하여 스케일 아웃 및 장기 보관 기능을 추가할 수 있습니다.

    Prometheus 및 Grafana 기반 쿠버네티스 모니터링 시스템의 주요 이점과 활용 방안을 요약한 인포그래픽입니다.

    맺음말: 13년차 엔지니어의 조언

    쿠버네티스 모니터링은 클러스터 운영의 핵심이자, 인프라 엔지니어의 역량을 보여주는 중요한 부분입니다. 처음에는 어렵게 느껴질 수 있지만, 이렇게 직접 구축하고 활용해보면서 얻는 경험은 그 어떤 이론보다 값지다고 생각합니다. 저도 13년차 엔지니어이지만, 여전히 새로운 기술을 배우고 직접 손으로 만져보면서 배우는 것이 가장 즐겁고 효과적하더라고요.

    오늘 제가 공유한 내용이 여러분의 쿠버네티스 여정에 작은 도움이 되었기를 바랍니다. 혹시 진행 중에 궁금한 점이나 막히는 부분이 있다면 언제든지 댓글로 남겨주세요. 제가 아는 선에서 최대한 도와드리겠습니다. 다음에는 Alertmanager 설정이나 Custom Exporter 개발 경험에 대해서도 다뤄볼 예정이니 기대해주세요!

    다음 글에서 또 만나요! ✋