작성일 댓글 남기기

OpenTelemetry로 시작하는 관측성 실전 구축 가이드

관측성 개념을 시각화한 데이터 흐름 일러스트

서비스를 운영하다 보면 누구나 한 번쯤은 이런 경험을 하게 됩니다. 새벽에 알림이 울려 대시보드를 열어봤더니 CPU 사용률이 치솟아 있는데, 도대체 어떤 요청이 문제인지 알 수 없는 상황. 로그를 뒤져봐도 에러 메시지는 없고, 메트릭만 빨간색으로 반짝이고 있죠. 결국 여러 서버를 돌아다니며 로그를 하나하나 grep 하다가 두 시간이 훌쩍 지나버립니다.

이런 상황이 반복된다면, 지금 여러분의 시스템에는 모니터링은 있지만 관측성(Observability)이 없는 것입니다. 모니터링은 미리 정해둔 지표가 임곗값을 넘으면 알림을 보내는 것이고, 관측성은 시스템 외부에서 내부 상태를 추론할 수 있게 해주는 능력입니다. 모니터링이 “무엇이 고장났는가”를 알려준다면, 관측성은 “왜 고장났는가”까지 답할 수 있게 해줍니다.

2026년 현재, 마이크로서비스와 클라우드 네이티브 아키텍처가 보편화되면서 관측성은 선택이 아닌 필수가 되었습니다. 서비스 하나가 수십 개의 컨테이너에 분산되어 동작하는 환경에서 전통적인 모니터링만으로는 문제를 진단할 수 없기 때문이죠. 그리고 이 관측성의 세계에서 사실상 표준으로 자리 잡은 것이 바로 OpenTelemetry입니다. 이 글에서는 OpenTelemetry를 중심으로 관측성의 핵심 개념부터 실제 구축 방법, 비용 최적화 전략까지 실전에서 바로 써먹을 수 있는 내용을 다뤄보겠습니다.

관측성의 세 기둥: 로그, 메트릭, 트레이스

관측성을 이야기할 때 빠지지 않고 등장하는 것이 바로 세 기둥(Three Pillars)입니다. 로그, 메트릭, 트레이스 — 이 세 가지 텔레메트리 데이터가 관측성의 토대를 이룹니다. 각각의 역할이 다르고, 셋이 합쳐졌을 때 비로소 시스템을 입체적으로 이해할 수 있게 됩니다.

관측성 세 기둥 로그 메트릭 트레이스 관계도

로그(Logs): 무슨 일이 일어났는가

로그는 가장 익숙한 텔레메트리 데이터입니다. 애플리케이션이 특정 시점에 발생한 이벤트를 텍스트 형태로 기록한 것이죠. “2026-05-31T09:15:23Z ERROR 주문 처리 실패: 재고 부족 (product_id=A1234)” 같은 형태가 전형적인 로그입니다.

로그의 강점은 맥락이 풍부하다는 점입니다. 에러 메시지, 스택 트레이스, 요청 파라미터 등 디버깅에 필요한 세부 정보를 담을 수 있습니다. 하지만 단점도 명확합니다. 비정형(unstructured) 로그는 검색과 집계가 어렵고, 대량으로 쌓이면 저장 비용이 급격히 늘어납니다.

그래서 현대적인 관측성 환경에서는 구조화 로그(Structured Logging)를 사용합니다. JSON 형태로 로그를 남기면 필드 단위로 검색·필터링·집계가 가능해집니다. 예를 들어 {“level”:”error”, “service”:”order-api”, “trace_id”:”abc123″, “message”:”재고 부족”}처럼 기록하면, 나중에 특정 trace_id로 해당 요청의 전체 경로를 추적할 수 있게 됩니다.

메트릭(Metrics): 얼마나 잘 동작하는가

메트릭은 시간에 따른 수치 데이터입니다. CPU 사용률, 메모리 점유율, 요청 처리 시간(latency), 초당 요청 수(throughput), 에러율 같은 것들이죠. 로그가 개별 이벤트를 기록한다면, 메트릭은 전체적인 추세와 패턴을 보여줍니다.

메트릭의 가장 큰 장점은 저장 효율입니다. 1분마다 하나의 숫자를 기록하기 때문에 수천 개의 메트릭을 수년간 보관해도 용량이 크지 않습니다. 또한 대시보드에서 실시간으로 시각화하기에 최적이고, 임곗값 기반 알림 설정도 자연스럽습니다.

관측성 관점에서 메트릭이 특히 중요한 이유는 RED 메서드USE 메서드 같은 체계적인 프레임워크가 있기 때문입니다. RED(Rate, Errors, Duration)는 서비스 수준에서 상태를 파악하는 데 쓰이고, USE(Utilization, Saturation, Errors)는 인프라 리소스 상태를 진단하는 데 활용됩니다. 이 두 가지를 함께 보면 “느린 건 알겠는데 왜 느린지 모르겠다”는 상황을 크게 줄일 수 있습니다.

트레이스(Traces): 요청이 어떻게 흘러갔는가

분산 트레이싱은 마이크로서비스 환경에서 관측성의 핵심입니다. 하나의 사용자 요청이 여러 서비스를 거치며 처리되는 과정을 시각적으로 추적할 수 있게 해줍니다. API 게이트웨이 → 주문 서비스 → 재고 서비스 → 결제 서비스 → 알림 서비스로 이어지는 요청 흐름에서 어디서 지연이 발생하는지, 어디서 에러가 나는지를 한눈에 파악할 수 있죠.

트레이스는 스팬(Span)이라는 단위로 구성됩니다. 각 스팬은 하나의 작업 단위를 나타내며, 시작 시간, 종료 시간, 상태, 속성(attributes) 등을 포함합니다. 스팬들은 부모-자식 관계로 연결되어 하나의 트레이스 트리를 형성합니다. 이 트리를 워터폴(Waterfall) 차트로 시각화하면, 전체 요청 중 어떤 단계에서 시간이 가장 많이 소요되는지 직관적으로 알 수 있습니다.

세 기둥의 상관관계가 진짜 힘이다

로그, 메트릭, 트레이스 각각도 유용하지만, 진정한 관측성의 힘은 이 셋이 상관관계(Correlation)로 연결될 때 발휘됩니다. 메트릭 대시보드에서 에러율 급증을 발견하면 해당 시간대의 트레이스로 넘어가서 실패한 요청을 찾고, 그 트레이스에 연결된 로그에서 구체적인 에러 원인을 확인하는 것이죠. trace_id라는 하나의 식별자가 로그와 트레이스를 관통하며, 메트릭에는 exemplar라는 기능으로 특정 데이터 포인트를 대표 트레이스와 연결합니다.

이런 상관관계가 바로 “왜 고장났는가”에 답할 수 있는 관측성의 본질입니다. 그리고 이 세 가지 데이터를 일관된 방식으로 수집·전송하는 표준이 바로 OpenTelemetry입니다.

OpenTelemetry: 관측성의 사실상 표준

OpenTelemetry(줄여서 OTel)는 CNCF(Cloud Native Computing Foundation)가 관리하는 오픈소스 관측성 프레임워크입니다. 2019년에 OpenTracing과 OpenCensus 두 프로젝트가 합쳐져 탄생했으며, 2026년 현재 Kubernetes 다음으로 CNCF에서 가장 활발한 프로젝트로 성장했습니다.

OpenTelemetry 컬렉터 아키텍처 구성도

왜 OpenTelemetry인가

OpenTelemetry가 등장하기 전에는 각 관측성 벤더마다 자체 에이전트, 자체 SDK, 자체 프로토콜을 사용했습니다. Datadog 에이전트, New Relic 에이전트, Jaeger 클라이언트, Zipkin 라이브러리… 벤더를 바꾸려면 계측(instrumentation) 코드를 전부 뜯어고쳐야 했죠. 이것은 사실상 벤더 종속(Vendor Lock-in)이었습니다.

OpenTelemetry는 이 문제를 해결합니다. 계측은 OTel SDK로 한 번만 하고, 수집한 데이터를 어디로 보낼지는 설정만 바꾸면 됩니다. Jaeger에서 Grafana Tempo로, 혹은 Datadog으로 백엔드를 자유롭게 전환할 수 있습니다. 이런 유연성 덕분에 대부분의 관측성 벤더들이 OTel을 공식 지원하게 되었고, 사실상 업계 표준이 된 것입니다.

OpenTelemetry의 핵심 구성 요소

OTel은 크게 세 가지 구성 요소로 이루어져 있습니다.

첫 번째는 API와 SDK입니다. API는 언어별로 제공되는 인터페이스로, 애플리케이션 코드에서 텔레메트리 데이터를 생성하는 방법을 정의합니다. SDK는 이 API의 구현체로, 데이터 처리, 배치 전송, 샘플링 등 실제 동작을 담당합니다. Python, Java, Go, JavaScript, .NET, Rust 등 주요 언어를 모두 지원합니다.

두 번째는 자동 계측(Auto-instrumentation)입니다. 코드를 한 줄도 수정하지 않고 텔레메트리를 수집할 수 있게 해주는 기능입니다. Python의 경우 opentelemetry-instrument 명령어 하나로 Flask, Django, FastAPI, requests, SQLAlchemy 같은 라이브러리의 호출을 자동으로 추적합니다. Java는 javaagent 방식으로 동작하며, Node.js도 자동 계측을 지원합니다. 자동 계측만으로도 서비스 간 호출, DB 쿼리, HTTP 요청 등 대부분의 외부 통신을 트레이싱할 수 있습니다.

세 번째는 OpenTelemetry Collector입니다. 관측성 데이터의 허브 역할을 하는 독립 프로세스입니다. 애플리케이션이 보낸 텔레메트리 데이터를 받아서(Receiver), 변환·필터링·보강하고(Processor), 최종 백엔드로 전달합니다(Exporter). Collector를 사이에 두면 애플리케이션은 백엔드의 종류를 몰라도 되고, Collector 설정만 바꿔서 데이터 경로를 자유자재로 제어할 수 있습니다.

OTLP: 텔레메트리의 공용어

OpenTelemetry Protocol(OTLP)은 OTel이 정의한 텔레메트리 데이터 전송 프로토콜입니다. gRPC와 HTTP 두 가지 전송 방식을 지원하며, 로그, 메트릭, 트레이스 세 종류의 데이터를 모두 하나의 프로토콜로 전송할 수 있습니다. 대부분의 관측성 백엔드가 OTLP를 네이티브로 지원하기 때문에, OTLP로 데이터를 보내기만 하면 어떤 백엔드든 연결할 수 있습니다.

실전 구축: 오픈소스 관측성 스택 한 번에 올리기

이론은 충분히 살펴봤으니, 이제 실제로 관측성 환경을 구축해보겠습니다. 상용 SaaS를 쓰면 간편하지만 비용이 만만치 않죠. 여기서는 완전히 무료인 오픈소스 도구들로 로컬 환경에 관측성 스택을 세팅하는 방법을 다룹니다. 사이드 프로젝트나 소규모 팀이라면 이 구성으로 충분히 실용적인 관측성을 확보할 수 있습니다.

Grafana LGTM 오픈소스 관측성 스택 구성도

스택 구성: Grafana LGTM

오픈소스 관측성 스택으로 가장 많이 쓰이는 조합은 Grafana가 주도하는 LGTM 스택입니다.

  • Loki — 로그 집계 시스템. Prometheus에서 영감을 받아 설계되었으며, 로그 내용 자체는 인덱싱하지 않고 레이블만 인덱싱하여 저장 비용을 획기적으로 낮춥니다.
  • Grafana — 시각화 대시보드. 메트릭, 로그, 트레이스를 하나의 UI에서 모두 조회하고, 상관관계를 탐색할 수 있습니다.
  • Tempo — 분산 트레이스 백엔드. 오브젝트 스토리지에 트레이스를 저장하므로 운영이 간편하고 비용 효율적입니다.
  • Mimir(또는 Prometheus) — 메트릭 저장소. 소규모라면 Prometheus 단독으로, 대규모라면 장기 보관과 수평 확장이 가능한 Mimir를 사용합니다.

여기에 OpenTelemetry Collector를 앞단에 놓으면 애플리케이션에서 보내는 모든 텔레메트리 데이터를 하나의 엔드포인트로 수신한 뒤 각 백엔드로 분배할 수 있습니다.

Docker Compose로 로컬에 띄우기

실전 환경에서는 Kubernetes에 Helm Chart로 배포하는 것이 일반적이지만, 로컬에서 빠르게 시작하려면 Docker Compose가 최적입니다. 핵심 구성 요소를 살펴보겠습니다.

먼저 OpenTelemetry Collector의 설정 파일(otel-collector-config.yaml)입니다. Collector가 어떤 데이터를 받아서 어디로 보낼지 정의하는 핵심 파일이죠.

Receiver 섹션에서는 OTLP 프로토콜의 gRPC(4317 포트)와 HTTP(4318 포트)를 모두 열어둡니다. 애플리케이션이 어떤 방식으로 데이터를 보내든 수신할 수 있게 하기 위해서입니다.

Processor 섹션에서는 batch processor를 설정합니다. 텔레메트리 데이터를 건건이 보내면 네트워크 오버헤드가 크기 때문에, 일정 시간(예: 5초) 또는 일정 건수(예: 1024건) 동안 모아서 한꺼번에 전송합니다. 이 설정 하나로 네트워크 효율이 크게 개선됩니다.

Exporter 섹션에서는 각 백엔드의 엔드포인트를 지정합니다. 트레이스는 Tempo(tempo:4317)로, 메트릭은 Prometheus remote write 엔드포인트로, 로그는 Loki(loki:3100)로 보내도록 설정합니다.

마지막으로 Pipeline 섹션에서 이 세 가지를 연결합니다. traces, metrics, logs 각각에 대해 receiver → processor → exporter 파이프라인을 정의하면 데이터 흐름이 완성됩니다.

애플리케이션 계측: Python 예시

실제 애플리케이션에 OpenTelemetry를 적용하는 방법을 Python FastAPI 기준으로 살펴보겠습니다. 가장 빠른 방법은 자동 계측입니다.

우선 필요한 패키지를 설치합니다. opentelemetry-distroopentelemetry-exporter-otlp를 pip로 설치하고, opentelemetry-bootstrap -a install 명령을 실행하면 현재 환경에 설치된 라이브러리(FastAPI, httpx, SQLAlchemy 등)에 맞는 자동 계측 패키지가 자동으로 설치됩니다.

그 다음 애플리케이션을 실행할 때 opentelemetry-instrument 명령을 앞에 붙여주면 됩니다. 환경변수로 서비스 이름, Collector 엔드포인트, 로그 내보내기 활성화 여부 등을 지정합니다.

이것만으로도 HTTP 요청/응답, DB 쿼리, 외부 API 호출 등에 대한 트레이스가 자동으로 생성됩니다. 코드를 한 줄도 수정하지 않았는데 Grafana에서 요청 흐름을 추적할 수 있게 되는 것이죠.

물론 자동 계측만으로는 비즈니스 로직 수준의 세밀한 추적이 어렵습니다. 특정 함수의 실행 시간을 측정하거나, 주문 ID 같은 비즈니스 속성을 스팬에 추가하고 싶다면 수동 계측을 함께 사용합니다. OTel SDK의 tracer를 가져와서 with 구문으로 커스텀 스팬을 만들고, set_attribute로 원하는 속성을 추가하면 됩니다. 자동 계측이 큰 틀을 잡아주고, 수동 계측으로 비즈니스 맥락을 보강하는 것이 가장 효과적인 패턴입니다.

Grafana에서 상관관계 탐색하기

데이터가 수집되기 시작하면, Grafana에서 진정한 관측성을 체험할 수 있습니다. Grafana의 강점은 데이터소스 간 연결입니다.

Prometheus 데이터소스의 Exemplar 기능을 활성화하면, 메트릭 그래프 위에 작은 점들이 나타납니다. 이 점을 클릭하면 해당 시점의 대표 트레이스로 바로 이동합니다. “응답 시간 99퍼센타일이 왜 이렇게 높지?” → 클릭 → 느린 요청의 전체 경로를 워터폴 차트로 확인 → 특정 DB 쿼리에서 800ms가 걸린 것을 발견. 이 흐름이 가능해집니다.

Tempo의 트레이스 상세 화면에서는 각 스팬에 연결된 로그를 바로 조회할 수 있습니다. trace_id가 로그의 필드에 포함되어 있기 때문에, Loki에서 해당 trace_id로 필터링한 로그가 자동으로 표시됩니다. 에러가 발생한 스팬을 클릭하면 그 시점에 기록된 에러 로그와 스택 트레이스를 즉시 확인할 수 있습니다.

이러한 메트릭 → 트레이스 → 로그의 드릴다운 경로가 바로 관측성이 모니터링과 근본적으로 다른 점입니다. 미리 정해둔 대시보드만 보는 것이 아니라, 문제를 발견한 지점에서 출발하여 원인까지 자유롭게 탐색할 수 있는 것이죠.

관측성 데이터 비용 최적화 전략

관측성을 도입한 뒤 가장 흔하게 마주치는 문제가 바로 데이터 폭증입니다. 모든 요청의 모든 스팬을 저장하고, 모든 로그를 보관하고, 수천 개의 메트릭 시계열을 유지하다 보면 저장 비용과 쿼리 성능 모두 감당하기 어려워집니다. 특히 SaaS 관측성 플랫폼을 사용하는 경우 데이터량에 비례하여 과금되기 때문에, 최적화 없이는 말 그대로 비용 폭탄을 맞을 수 있습니다.

헤드 기반과 테일 기반 트레이스 샘플링 전략 비교

트레이스 샘플링: 모든 것을 저장할 필요는 없다

트레이스는 관측성 데이터 중 가장 용량이 큽니다. 초당 수천 건의 요청을 처리하는 서비스에서 모든 트레이스를 저장하면 하루에 수 기가바이트가 쌓이죠. 하지만 실제로 분석에 필요한 트레이스는 전체의 극히 일부입니다. 여기서 샘플링이 등장합니다.

헤드 기반 샘플링(Head-based Sampling)은 가장 단순한 방식입니다. 요청이 시작되는 시점에 “이 트레이스를 수집할지 말지”를 확률적으로 결정합니다. 예를 들어 샘플링 비율을 10%로 설정하면, 10개 중 1개의 트레이스만 저장됩니다. 구현이 간단하고 예측 가능하지만, 중요한 에러 트레이스가 버려질 수 있다는 단점이 있습니다.

테일 기반 샘플링(Tail-based Sampling)은 이 문제를 해결합니다. 트레이스의 모든 스팬이 완료된 후에 샘플링 여부를 결정하는 방식입니다. 에러가 포함된 트레이스, 응답 시간이 비정상적으로 긴 트레이스는 100% 보관하고, 정상적인 트레이스는 낮은 비율로만 저장합니다. OpenTelemetry Collector의 tail_sampling processor를 사용하면 이를 쉽게 구현할 수 있습니다.

테일 기반 샘플링의 정책 예시를 보겠습니다. 에러 상태 코드가 포함된 트레이스는 무조건 보관, 응답 시간이 2초를 초과하는 트레이스도 무조건 보관, 특정 서비스(결제 서비스 등)의 트레이스는 50%를 보관, 나머지는 5%만 보관. 이런 식으로 중요한 데이터는 놓치지 않으면서 전체 저장량을 크게 줄일 수 있습니다.

다만 테일 기반 샘플링은 Collector가 트레이스의 모든 스팬을 메모리에 잠시 보관해야 하므로, Collector의 리소스 사용량이 늘어난다는 점을 고려해야 합니다. 대규모 트래픽 환경에서는 Collector를 두 단계로 분리하여, 첫 번째 단계에서 데이터를 수집하고 두 번째 단계에서 샘플링을 수행하는 구성을 권장합니다.

로그 최적화: 레벨과 구조가 핵심

로그 비용을 줄이는 가장 효과적인 방법은 로그 레벨 관리입니다. 프로덕션 환경에서 DEBUG 레벨 로그를 남기면 데이터량이 10배 이상 늘어날 수 있습니다. 기본은 INFO 이상으로 설정하고, 특정 모듈만 디버깅이 필요할 때 동적으로 레벨을 낮추는 방식이 효율적입니다.

로그 필터링과 변환도 OpenTelemetry Collector에서 처리할 수 있습니다. filter processor를 사용하면 특정 조건의 로그를 드롭하거나, transform processor로 불필요한 필드를 제거하거나, attributes processor로 민감 정보를 마스킹할 수 있습니다. 이렇게 Collector 단계에서 데이터를 정제하면 백엔드 저장소의 부하와 비용을 효과적으로 관리할 수 있습니다.

Loki를 사용한다면 레이블 설계에도 주의를 기울여야 합니다. Loki는 레이블 조합별로 스트림을 생성하는데, 레이블의 카디널리티(고유 값의 수)가 너무 높으면 스트림 수가 폭증하여 성능이 저하됩니다. service, environment, level 정도의 저카디널리티 레이블만 인덱스에 사용하고, request_id나 user_id 같은 고카디널리티 값은 로그 본문에 구조화 필드로 남기는 것이 좋습니다.

메트릭 최적화: 카디널리티 관리

메트릭에서 가장 주의해야 할 것은 카디널리티 폭발(Cardinality Explosion)입니다. 메트릭의 레이블에 사용자 ID, 세션 ID, 요청 경로(파라미터 포함) 같은 고유 값을 넣으면 시계열 수가 기하급수적으로 늘어납니다. 예를 들어 HTTP 요청 메트릭에 전체 URL 경로를 레이블로 넣으면, /users/1, /users/2, … /users/100000 각각이 별도의 시계열이 되어 Prometheus가 메모리 부족으로 죽을 수 있습니다.

해결책은 URL 패턴을 정규화하는 것입니다. /users/12345를 /users/{id}로 변환하여 레이블에 넣으면 시계열 수를 극적으로 줄일 수 있습니다. OpenTelemetry의 HTTP 관련 계측 라이브러리들은 대부분 이런 정규화를 기본으로 지원합니다.

또한 불필요한 메트릭 드롭도 효과적입니다. 자동 계측이 생성하는 메트릭 중 실제로 사용하지 않는 것들이 있을 수 있습니다. Collector의 filter processor나 Prometheus의 metric_relabel_configs로 불필요한 메트릭을 저장 전에 제거하면 스토리지 비용을 절약할 수 있습니다.

관측성 도입 시 흔한 실수와 대처법

관측성을 처음 도입하는 팀에서 자주 저지르는 실수들이 있습니다. 미리 알고 피하면 시행착오를 크게 줄일 수 있습니다.

실수 1: 모든 것을 한꺼번에 도입하려고 한다

로그, 메트릭, 트레이스를 동시에 모든 서비스에 적용하려는 것은 거의 확실히 실패합니다. 대신 점진적 접근을 권합니다. 가장 효과가 큰 하나부터 시작하세요. 마이크로서비스 환경이라면 분산 트레이싱부터, 모놀리식이라면 구조화 로그부터 시작하는 것이 보통입니다. 한 가지를 안정화한 뒤 다음을 추가하면 학습 곡선도 완만하고, 각 단계에서 가시적인 성과를 얻을 수 있습니다.

실수 2: 대시보드만 만들고 알림을 설정하지 않는다

아무리 훌륭한 대시보드를 만들어도 아무도 24시간 지켜보지 않습니다. 관측성의 가치는 문제가 생겼을 때 빠르게 인지하고 빠르게 진단하는 데 있습니다. 핵심 SLI(Service Level Indicator)에 대한 알림을 반드시 설정하세요. 에러율이 1%를 넘으면, P99 응답 시간이 3초를 넘으면, 큐 적체량이 1000건을 넘으면 — 이런 구체적인 조건으로 알림을 만들어야 합니다.

실수 3: 계측 코드를 비즈니스 로직에 깊이 심는다

관측성 코드가 비즈니스 로직과 뒤엉키면 유지보수가 어려워집니다. OpenTelemetry의 자동 계측을 최대한 활용하고, 수동 계측이 필요한 경우에도 데코레이터, 미들웨어, 컨텍스트 매니저 같은 래핑 패턴으로 분리하세요. 계측 코드는 언제든 제거하거나 변경할 수 있어야 합니다.

실수 4: 관측성을 개발 초기가 아닌 장애 후에 도입한다

“아직 서비스가 작은데 관측성까지 필요한가”라는 생각은 자연스럽지만, 관측성은 서비스가 작을 때 도입하는 것이 훨씬 쉽습니다. 서비스가 복잡해진 뒤에 사후적으로 계측을 추가하려면 코드 베이스 전체를 훑어야 하고, 이미 발생한 장애의 원인은 과거 데이터가 없어서 분석이 불가능합니다. OpenTelemetry의 자동 계측 덕분에 초기 도입 비용은 매우 낮으니, 가능한 한 빨리 시작하는 것이 현명합니다.

2026년 관측성 트렌드: 주목할 만한 흐름

마지막으로 관측성 분야에서 주목할 만한 최신 트렌드를 간략히 짚어보겠습니다.

eBPF 기반 관측성

eBPF(extended Berkeley Packet Filter)를 활용한 관측성 도구가 빠르게 성장하고 있습니다. eBPF는 리눅스 커널 레벨에서 동작하기 때문에 애플리케이션 코드를 전혀 수정하지 않고도 네트워크 트래픽, 시스템 콜, 파일 I/O 등을 관측할 수 있습니다. Cilium의 Hubble, Grafana의 Beyla 같은 도구가 대표적이며, 특히 사이드카 없이 서비스 메시 수준의 관측성을 확보할 수 있다는 점에서 Kubernetes 환경에서 각광받고 있습니다.

연속 프로파일링(Continuous Profiling)

로그, 메트릭, 트레이스에 이어 프로파일이 관측성의 네 번째 기둥으로 부상하고 있습니다. Grafana Pyroscope, Parca 같은 오픈소스 도구로 프로덕션 환경의 CPU, 메모리 프로파일을 상시 수집할 수 있게 되었습니다. 트레이스에서 특정 스팬이 느린 것을 발견했을 때, 해당 시점의 프로파일로 드릴다운하면 어떤 함수가 CPU를 많이 사용했는지까지 확인할 수 있습니다. OpenTelemetry도 프로파일링 시그널을 공식 지원하기 시작했으며, 향후 네 가지 시그널이 완전히 통합될 것으로 기대됩니다.

AI 기반 이상 탐지

수천 개의 메트릭과 수백만 줄의 로그를 사람이 일일이 모니터링하는 것은 불가능합니다. AI/ML 기반 이상 탐지(Anomaly Detection)가 이 문제를 보완하고 있습니다. 정상 패턴을 학습한 모델이 비정상적인 메트릭 변동이나 로그 패턴을 자동으로 감지하고, 관련된 트레이스와 로그를 자동으로 상관시켜 알림을 보내는 것이죠. Datadog, Dynatrace 같은 상용 플랫폼이 선도하고 있지만, 오픈소스 진영에서도 Grafana의 ML 기능이나 별도의 이상 탐지 파이프라인을 구축하는 사례가 늘고 있습니다.

마무리: 작게 시작하고, 꾸준히 확장하기

관측성은 한 번 구축하고 끝나는 프로젝트가 아닙니다. 서비스가 성장하고 아키텍처가 변화함에 따라 관측성도 함께 진화해야 합니다. 하지만 첫걸음은 생각보다 어렵지 않습니다.

오늘 당장 시작할 수 있는 가장 작은 단계를 제안합니다. 여러분의 프로젝트에 OpenTelemetry 자동 계측을 적용해보세요. Python이라면 패키지 두 개 설치하고 실행 명령어만 바꾸면 됩니다. 그리고 Docker Compose로 Grafana + Tempo를 띄워서 트레이스를 시각화해보세요. 여러분의 서비스 내부에서 요청이 어떻게 흘러가는지 처음으로 눈에 보이는 순간, 관측성의 가치를 체감하게 될 것입니다.

모니터링이 “이상 있음”을 알려주는 화재 경보기라면, 관측성은 “왜 불이 났고 어디서 시작됐는지”를 보여주는 투시경입니다. 서비스 규모에 상관없이, 지금 시작하는 것이 가장 좋은 타이밍입니다.

이미지는 Leonardo AI 로 생성되었습니다.

이미지는 Claude AI 로 생성되었습니다.

작성일 댓글 남기기

Grafana 홈서버 모니터링 대시보드 만들기 – 설치부터 알림까지

Grafana 모니터링 대시보드가 표시된 모니터

내 서버 상태, 눈으로 바로 확인할 수 있다면?

홈서버나 NAS를 운영하다 보면 문득 궁금해질 때가 있습니다. 지금 CPU는 얼마나 쓰고 있는 걸까? 메모리는 괜찮은가? 디스크가 슬슬 부족하진 않나? SSH로 접속해서 htop을 실행하거나 df -h를 입력하면 확인할 수 있지만, 매번 터미널을 열기엔 번거롭습니다. 더 큰 문제는 ‘과거 데이터’입니다. 지금 이 순간의 CPU 사용률은 확인할 수 있어도, 어제 새벽 3시에 갑자기 CPU가 100%를 찍었는지는 알 수 없죠.

이런 고민을 한 방에 해결해주는 조합이 바로 Grafana + Prometheus + Node Exporter입니다. 이 세 가지를 Docker로 설치하면, 웹 브라우저에서 예쁜 대시보드로 서버 상태를 실시간으로 확인할 수 있습니다. 과거 이력도 자동으로 저장되고, 디스크 사용률이 90%를 넘으면 텔레그램이나 이메일로 알림까지 보내줍니다. 이 글에서는 리눅스 기본 지식만 있으면 누구든 따라 할 수 있도록 처음부터 끝까지 상세하게 안내합니다.

Grafana Prometheus Node Exporter 아키텍처

Grafana, Prometheus, Node Exporter가 뭔가요?

세 가지 도구의 역할을 간단히 정리하면 이렇습니다. 비유하자면, Node Exporter는 ‘체온계’, Prometheus는 ‘차트에 기록하는 간호사’, Grafana는 ‘환자 상태를 보여주는 모니터’입니다.

Node Exporter – 서버 지표 수집기

Node Exporter는 서버의 하드웨어·OS 지표를 수집해서 HTTP 엔드포인트로 노출하는 경량 에이전트입니다. CPU 사용률, 메모리 사용량, 디스크 I/O, 네트워크 트래픽, 파일시스템 사용률 등 수백 가지 메트릭을 자동으로 수집합니다. 설치 후 별도 설정 없이 바로 동작하며, 리소스 소비도 극히 적습니다(메모리 10~20MB 수준).

Prometheus – 시계열 데이터베이스

Prometheus는 CNCF(Cloud Native Computing Foundation) 졸업 프로젝트로, 시계열(time-series) 데이터 수집·저장·쿼리에 특화된 모니터링 시스템입니다. 일정 간격(기본 15초)으로 Node Exporter 같은 대상에서 메트릭을 ‘풀(pull)’ 방식으로 가져와 로컬 디스크에 저장합니다. 자체 쿼리 언어인 PromQL을 통해 “최근 5분간 CPU 사용률 평균”이나 “디스크 여유 공간이 10GB 미만인 파티션”처럼 복잡한 질의가 가능합니다.

Grafana – 시각화 대시보드

Grafana는 데이터를 아름다운 그래프와 차트로 시각화해주는 오픈소스 대시보드 도구입니다. Prometheus뿐 아니라 MySQL, PostgreSQL, Elasticsearch, InfluxDB 등 다양한 데이터 소스를 지원합니다. 커뮤니티에서 만든 수천 개의 대시보드 템플릿을 무료로 가져와 바로 사용할 수 있다는 것이 가장 큰 장점입니다. 알림(Alert) 기능도 내장되어 있어 별도의 알림 시스템 없이도 텔레그램, 슬랙, 이메일 등으로 장애 알림을 보낼 수 있습니다.

사전 준비 – Docker와 Docker Compose 확인

이 가이드에서는 모든 것을 Docker Compose로 설치합니다. 먼저 서버에 Docker와 Docker Compose가 설치되어 있는지 확인하세요.

docker --version
docker compose version

두 명령어 모두 버전 정보가 출력되면 준비 완료입니다. 만약 설치되어 있지 않다면, 공식 문서를 참고하거나 이 블로그의 Docker 입문 포스트를 참고하세요. Synology NAS를 사용하신다면 패키지 센터에서 Container Manager(구 Docker)를 설치하면 됩니다.

이번 가이드에서 사용할 포트는 다음과 같습니다. 기존에 사용 중인 포트와 충돌하지 않는지 미리 확인해 두세요.

  • 3000 – Grafana 웹 대시보드
  • 9090 – Prometheus 웹 UI
  • 9100 – Node Exporter 메트릭 엔드포인트

1단계: 프로젝트 디렉터리 구성

깔끔한 관리를 위해 전용 디렉터리를 만들고, 그 안에 설정 파일과 데이터를 모아둡니다.

mkdir -p ~/monitoring/{prometheus,grafana}
cd ~/monitoring

최종 디렉터리 구조는 이렇게 됩니다.

~/monitoring/
├── docker-compose.yml
├── prometheus/
│   └── prometheus.yml
└── grafana/
    └── (Grafana 데이터가 자동 저장됩니다)

2단계: Prometheus 설정 파일 작성

Prometheus가 어디서 메트릭을 수집할지 알려주는 설정 파일을 작성합니다.

# ~/monitoring/prometheus/prometheus.yml

global:
  scrape_interval: 15s          # 15초마다 메트릭 수집
  evaluation_interval: 15s       # 15초마다 알림 규칙 평가

scrape_configs:
  # Prometheus 자체 모니터링
  - job_name: 'prometheus'
    static_configs:
      - targets: ['prometheus:9090']

  # Node Exporter (서버 리소스 모니터링)
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']

여기서 targets에 적힌 ‘prometheus’와 ‘node-exporter’는 Docker Compose 서비스 이름입니다. Docker 내부 네트워크에서 서비스 이름으로 서로를 찾을 수 있기 때문에 IP 주소를 적을 필요가 없습니다. 만약 다른 서버에 있는 Node Exporter를 모니터링하고 싶다면, 해당 서버의 IP와 포트(예: ‘192.168.1.100:9100’)를 추가하면 됩니다.

scrape_interval을 조절하면 어떻게 될까?

15초가 기본값이지만, 더 세밀한 모니터링이 필요하면 5초로 줄일 수 있고, 리소스를 아끼고 싶다면 30초나 60초로 늘릴 수 있습니다. 홈서버 용도라면 15초면 충분합니다. 수집 주기가 짧을수록 디스크 사용량이 늘어난다는 점만 기억하세요. 15초 간격으로 30일 보관 시 약 2~3GB 정도의 디스크 공간을 사용합니다.

Prometheus 설정 파일 핵심 구성요소 정리

3단계: Docker Compose 파일 작성

이제 핵심인 Docker Compose 파일을 작성합니다. 이 하나의 파일로 세 가지 서비스를 한 번에 실행합니다.

# ~/monitoring/docker-compose.yml

version: '3.8'

services:
  # 서버 메트릭 수집 에이전트
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    pid: host
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    networks:
      - monitoring

  # 시계열 데이터베이스
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'
    ports:
      - "9090:9090"
    networks:
      - monitoring
    depends_on:
      - node-exporter

  # 시각화 대시보드
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=changeme123
      - GF_SERVER_ROOT_URL=http://localhost:3000
    ports:
      - "3000:3000"
    networks:
      - monitoring
    depends_on:
      - prometheus

volumes:
  prometheus_data:
  grafana_data:

networks:
  monitoring:
    driver: bridge

몇 가지 중요한 포인트를 짚어보겠습니다.

  • node-exporter의 volumes: /proc, /sys, / 를 읽기 전용으로 마운트합니다. Docker 컨테이너 내부에서 호스트 시스템의 실제 리소스 정보를 읽어야 하기 때문입니다. pid: host 설정도 같은 이유입니다.
  • prometheus의 retention.time=30d: 메트릭 데이터를 30일간 보관합니다. 필요에 따라 늘리거나 줄일 수 있습니다.
  • web.enable-lifecycle: 이 옵션을 켜면 API 호출로 Prometheus 설정을 재로드할 수 있습니다. 컨테이너를 재시작하지 않아도 설정 변경이 반영되어 편리합니다.
  • grafana 비밀번호: 예시에서는 changeme123으로 설정했지만, 반드시 본인만 아는 강력한 비밀번호로 바꾸세요.
  • Named volume: prometheus_datagrafana_data를 Docker named volume으로 설정해 컨테이너를 삭제해도 데이터가 유지됩니다.

4단계: 서비스 실행 및 동작 확인

모든 파일이 준비되었으니 서비스를 실행합니다.

cd ~/monitoring
docker compose up -d

처음 실행하면 이미지를 다운로드하기 때문에 1~2분 정도 걸릴 수 있습니다. 완료 후 세 개의 컨테이너가 모두 실행 중인지 확인합니다.

docker compose ps

STATUS가 모두 Up으로 표시되어야 합니다. 이제 각 서비스가 정상 동작하는지 브라우저에서 확인해 봅니다.

Node Exporter 확인

브라우저에서 http://서버IP:9100/metrics에 접속합니다. 수백 줄의 텍스트가 쏟아져 나온다면 정상입니다. 이 텍스트 한 줄 한 줄이 서버의 상태를 나타내는 메트릭입니다. 예를 들어 node_cpu_seconds_total은 CPU 사용 시간, node_memory_MemAvailable_bytes는 사용 가능한 메모리 양을 나타냅니다.

Prometheus 확인

http://서버IP:9090에 접속합니다. Prometheus 웹 UI가 나타나면, 상단 메뉴에서 Status → Targets를 클릭합니다. ‘node’와 ‘prometheus’ 두 개의 타겟이 모두 UP 상태로 표시되어야 합니다. 만약 DOWN으로 표시된다면, Docker 네트워크 설정이나 prometheus.yml의 targets 주소를 다시 확인해 보세요.

Grafana 확인

http://서버IP:3000에 접속합니다. 로그인 화면이 나타나면 Docker Compose에서 설정한 ID(admin)와 비밀번호로 로그인합니다. 첫 로그인 시 비밀번호 변경을 권장하는 화면이 나올 수 있습니다.

5단계: Grafana에 Prometheus 데이터 소스 연결

Grafana에 로그인했다면, 이제 Prometheus를 데이터 소스로 등록해야 합니다.

  1. 왼쪽 사이드바에서 톱니바퀴(⚙️) → Data Sources를 클릭합니다.
  2. Add data source 버튼을 클릭합니다.
  3. 목록에서 Prometheus를 선택합니다.
  4. Connection 섹션의 Prometheus server URLhttp://prometheus:9090을 입력합니다. (Docker 내부 네트워크 이름을 사용합니다.)
  5. 나머지 설정은 기본값 그대로 두고 페이지 하단의 Save & Test를 클릭합니다.
  6. “Successfully queried the Prometheus API.” 메시지가 나오면 연결 성공입니다.

여기서 URL에 localhost가 아닌 prometheus를 사용하는 이유가 중요합니다. Grafana 컨테이너 입장에서 localhost는 자기 자신(Grafana 컨테이너)을 가리킵니다. Docker Compose의 같은 네트워크 안에 있는 Prometheus 컨테이너에 접근하려면 서비스 이름인 ‘prometheus’를 사용해야 합니다.

6단계: Node Exporter 대시보드 가져오기

Grafana의 진짜 강점은 커뮤니티 대시보드입니다. 직접 그래프를 하나하나 만들 필요 없이, 전문가들이 이미 만들어 놓은 완성도 높은 대시보드를 ID 하나로 가져올 수 있습니다.

  1. 왼쪽 사이드바에서 + → Import dashboard를 클릭합니다.
  2. Import via grafana.com 입력란에 1860을 입력하고 Load를 클릭합니다.
  3. 하단의 Prometheus 데이터 소스 드롭다운에서 방금 추가한 Prometheus를 선택합니다.
  4. Import를 클릭합니다.

짜잔! 순식간에 완성도 높은 모니터링 대시보드가 나타납니다. 1860번 대시보드는 “Node Exporter Full”이라는 이름으로, 가장 인기 있는 Node Exporter 대시보드입니다. 다운로드 수가 수천만 건에 달하며, CPU·메모리·디스크·네트워크를 한 화면에서 종합적으로 볼 수 있습니다.

Grafana 대시보드 패널 구성 예시

대시보드 상단에서 시간 범위를 조절할 수 있습니다. 기본은 최근 24시간이지만, 최근 1시간, 7일, 30일 등으로 자유롭게 변경할 수 있습니다. 우측 상단의 새로고침 아이콘 옆 드롭다운에서 자동 갱신 간격도 설정 가능합니다(5초, 10초, 30초 등).

추천 대시보드 ID 모음

1860번 외에도 유용한 대시보드가 많습니다.

  • 1860 – Node Exporter Full: 가장 포괄적인 서버 모니터링
  • 13978 – Node Exporter Quickstart: 핵심 지표만 깔끔하게
  • 893 – Docker 컨테이너 모니터링 (cAdvisor 필요)
  • 15489 – Nginx 모니터링 (nginx-prometheus-exporter 필요)
  • 7362 – MySQL 모니터링 (mysqld-exporter 필요)

필요한 Exporter를 추가로 설치하고, 해당 대시보드를 Import하면 모니터링 범위를 쉽게 확장할 수 있습니다.

7단계: 핵심 PromQL 쿼리 이해하기

대시보드를 그냥 쓰기만 해도 충분하지만, PromQL 기본 문법을 알아두면 커스텀 패널을 만들거나 알림 조건을 설정할 때 큰 도움이 됩니다.

CPU 사용률 (전체 평균)

100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

이 쿼리는 “최근 5분간 idle 상태가 아닌 CPU 시간의 비율”을 계산합니다. irate는 순간 변화율, avg는 모든 CPU 코어의 평균을 구합니다. 결과가 75라면 CPU를 75% 사용 중이라는 뜻입니다.

메모리 사용률

(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100

전체 메모리 대비 사용 중인 메모리의 비율을 퍼센트로 표시합니다. MemAvailable은 실제로 프로세스가 사용할 수 있는 메모리양이므로, 단순히 free 메모리보다 더 정확한 지표입니다.

디스크 사용률 (루트 파티션)

(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100

루트(/) 파티션의 디스크 사용률을 계산합니다. 다른 마운트 포인트를 모니터링하고 싶다면 mountpoint 값을 변경하면 됩니다.

네트워크 수신 트래픽 (초당)

irate(node_network_receive_bytes_total{device="eth0"}[5m]) * 8

eth0 인터페이스의 초당 수신 비트 수를 계산합니다. * 8은 바이트를 비트로 변환하기 위함입니다. 결과 단위는 bps입니다.

8단계: 알림(Alert) 설정하기

모니터링의 꽃은 알림입니다. 24시간 대시보드를 쳐다보고 있을 수는 없으니, 문제가 생기면 자동으로 알려주도록 설정합니다.

텔레그램 알림 연동

Grafana에서 텔레그램으로 알림을 보내려면 먼저 Contact Point를 설정해야 합니다.

  1. 왼쪽 사이드바에서 Alerting → Contact points로 이동합니다.
  2. + Add contact point를 클릭합니다.
  3. Name에 “Telegram”을 입력합니다.
  4. Integration 드롭다운에서 Telegram을 선택합니다.
  5. BOT API Token에 텔레그램 봇 토큰을 입력합니다.
  6. Chat ID에 알림을 받을 채팅방 ID를 입력합니다.
  7. Test 버튼으로 테스트 메시지를 보내보고, Save contact point를 클릭합니다.

텔레그램 봇이 없다면 @BotFather에게 메시지를 보내 새 봇을 만들 수 있습니다. Chat ID는 @userinfobot에게 메시지를 보내면 확인할 수 있습니다.

디스크 사용률 90% 초과 알림 규칙 만들기

  1. Alerting → Alert rules로 이동합니다.
  2. + New alert rule을 클릭합니다.
  3. Rule name에 “디스크 사용률 경고”를 입력합니다.
  4. 쿼리 섹션에서 데이터 소스를 Prometheus로 선택하고, 다음 쿼리를 입력합니다:
(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100
  1. Expressions 섹션에서 Threshold 조건을 IS ABOVE 90으로 설정합니다.
  2. Evaluation behavior에서 폴더를 선택하고, Evaluation group을 설정합니다. Pending period는 “5m”으로 설정합니다(5분간 지속될 때만 알림 발생).
  3. Labels and notifications에서 Contact point를 앞서 만든 “Telegram”으로 지정합니다.
  4. Save rule and exit를 클릭합니다.

Pending period를 5분으로 설정하는 이유가 중요합니다. 일시적인 스파이크로 인한 오탐(false positive)을 방지하기 위해서입니다. 디스크 사용률이 90%를 넘는 상태가 5분간 지속되어야만 실제 알림이 발생합니다.

자주 쓰는 알림 규칙 예시

  • CPU 사용률 85% 초과 (5분 지속): 서버 과부하 감지
  • 메모리 사용률 90% 초과 (5분 지속): 메모리 부족 경고
  • 디스크 사용률 90% 초과: 디스크 정리 필요 알림
  • 서버 다운 감지: up{job="node"} == 0 쿼리로 Node Exporter 응답 없음 감지
  • 네트워크 트래픽 급증: 평소 대비 비정상적 트래픽 감지
Grafana 알림 설정 흐름도

실전 팁: 운영하면서 알게 된 것들

1. Grafana 대시보드를 홈 화면으로 설정하기

매번 대시보드를 찾아 들어가기 번거롭다면, 자주 보는 대시보드를 홈 화면으로 설정할 수 있습니다. Administration → Default preferences에서 Home Dashboard를 지정하면, 로그인할 때마다 바로 그 대시보드가 보입니다.

2. 데이터 보관 기간과 디스크 공간 관리

Prometheus의 --storage.tsdb.retention.time=30d 설정으로 30일간 데이터를 보관하도록 했습니다. 메트릭이 많아질수록 디스크 사용량이 늘어나니, 주기적으로 Prometheus 컨테이너가 사용하는 볼륨 크기를 확인하세요.

docker system df -v | grep prometheus

장기 보관이 필요하다면 retention을 90d나 365d로 늘릴 수 있지만, 홈서버 수준에서는 30일이면 대부분의 트러블슈팅에 충분합니다.

3. 여러 대의 서버 모니터링하기

집에 서버가 여러 대 있다면 각 서버에 Node Exporter만 설치하고, Prometheus 설정에 타겟을 추가하면 됩니다.

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
          - 'node-exporter:9100'      # 로컬 서버
          - '192.168.1.100:9100'      # NAS
          - '192.168.1.101:9100'      # 미니 PC

Grafana 대시보드에서 상단 드롭다운으로 서버를 전환하며 각각의 상태를 확인할 수 있습니다.

4. 보안 고려사항

홈 네트워크 내부에서만 사용한다면 크게 걱정할 필요는 없지만, 외부에서 접속할 계획이라면 몇 가지를 반드시 챙기세요.

  • Grafana 관리자 비밀번호를 강력하게 설정
  • 포트를 외부에 직접 노출하지 말고, 리버스 프록시(Nginx Proxy Manager 등) + HTTPS 적용
  • Tailscale이나 VPN을 통해서만 접속 허용
  • Node Exporter 포트(9100)는 외부에 절대 공개하지 않기 – 서버 내부 정보가 그대로 노출됩니다

5. Docker 컨테이너 모니터링 추가하기

서버 리소스뿐 아니라 Docker 컨테이너별 리소스 사용량도 보고 싶다면 cAdvisor를 추가합니다. Docker Compose에 다음 서비스를 추가하세요.

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    restart: unless-stopped
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"
    networks:
      - monitoring

Prometheus 설정에 cAdvisor 타겟을 추가하고, Grafana에서 893번 대시보드를 Import하면 컨테이너별 CPU, 메모리, 네트워크 사용량을 실시간으로 확인할 수 있습니다.

트러블슈팅 가이드

설치 과정에서 자주 발생하는 문제와 해결 방법을 정리했습니다.

Prometheus Targets에서 node-exporter가 DOWN으로 표시될 때

가장 흔한 원인은 Docker 네트워크 설정입니다. docker compose ps로 node-exporter 컨테이너가 실행 중인지 확인하고, docker compose logs node-exporter로 에러 로그를 확인하세요. 네트워크가 올바르게 설정되어 있다면 대부분 컨테이너 재시작으로 해결됩니다.

Grafana에서 “No data” 표시가 나올 때

데이터 소스 URL이 정확한지 확인하세요. http://prometheus:9090이어야 합니다(http://localhost:9090이 아닙니다). Data Sources 설정에서 Save & Test를 다시 눌러보세요.

Grafana 비밀번호를 잊어버렸을 때

다음 명령어로 비밀번호를 초기화할 수 있습니다.

docker exec -it grafana grafana-cli admin reset-admin-password 새비밀번호

Prometheus 디스크 사용량이 너무 클 때

--storage.tsdb.retention.time 값을 줄이거나, --storage.tsdb.retention.size=5GB처럼 크기 제한을 추가하세요. 설정 변경 후 Prometheus 컨테이너를 재시작하면 오래된 데이터가 정리됩니다.

마치며 – 모니터링은 서버 운영의 기본 체력

Grafana + Prometheus + Node Exporter 스택은 기업 환경에서도 표준으로 사용되는 검증된 모니터링 솔루션입니다. 이 가이드대로 설치하면 약 20~30분 만에 프로 수준의 모니터링 환경을 갖출 수 있습니다. 처음에는 단순히 “CPU가 얼마나 쓰이는지” 확인하는 정도지만, 시간이 지나면서 쌓인 데이터가 진짜 가치를 발휘합니다. “지난달 이맘때보다 메모리 사용량이 늘었네”, “매주 화요일 새벽에 디스크 I/O가 급증하는 패턴이 있군” 같은 인사이트를 얻을 수 있고, 이런 데이터를 기반으로 사전에 문제를 예방할 수 있습니다.

서버를 운영한다면 모니터링은 선택이 아니라 필수입니다. 오늘 30분을 투자해서, 내 서버의 건강 상태를 한눈에 파악할 수 있는 대시보드를 만들어 보세요. 한 번 설치해 두면 매일 확인하게 되는 자신을 발견하게 될 겁니다.

이미지는 Leonardo AI 로 생성되었습니다.

이미지는 Claude AI 로 생성되었습니다.