TechFeedTechFeed
Open Source

Prometheus + Grafana 서버 모니터링 완전 가이드 — Docker 구축·Node Exporter·AlertManager 슬랙 알림까지

프로메테우스와 그라파나로 서버 모니터링 스택을 직접 구축하는 실전 가이드. Docker Compose 설치부터 Node Exporter 메트릭 수집, Node.js prom-client 애플리케이션 메트릭 노출, 그라파나 대시보드 설정, AlertManager 슬랙 알림 연동, 프로덕션 운영 팁까지 실제 동작하는 코드와 함께 정리합니다. 유료 서비스 없이 오픈소스로 완성하는 옵저버빌리티 기초.

by

서버가 새벽 3시에 조용히 멈췄습니다. CPU는 100%, 메모리는 바닥났는데 아무도 몰랐습니다. 그 경험 이후 저는 모든 서비스에 Prometheus(프로메테우스)와 Grafana(그라파나)를 먼저 올립니다.


프로메테우스와 그라파나는 개발자가 직접 구축할 수 있는 오픈소스 모니터링 스택의 표준입니다. Datadog나 New Relic 같은 유료 서비스보다 비용이 0에 가깝고, 데이터를 내 인프라에 보관할 수 있으며, 커스터마이징 자유도가 압도적입니다. 이 글에서는 Docker Compose로 두 도구를 설치하고, 서버 메트릭을 수집하고, 대시보드를 구성하고, 슬랙 알림까지 연결하는 전 과정을 실제로 동작하는 코드와 함께 정리합니다.


예상 소요 시간: 초기 구축 30분, AlertManager 연동 추가 20분. 도커가 설치된 서버가 있다면 바로 따라할 수 있습니다.


Prometheus란 무엇인가 — 풀 방식 메트릭 수집의 작동 원리

프로메테우스는 SoundCloud가 2012년 오픈소스로 공개한 시계열 데이터베이스이자 모니터링 시스템입니다. 2016년 CNCF(클라우드 네이티브 컴퓨팅 파운데이션)에 두 번째 프로젝트로 합류했고, 현재 쿠버네티스 생태계에서 사실상 표준 메트릭 수집 도구입니다.


프로메테우스의 핵심 철학은 풀(Pull) 방식입니다. 기존 모니터링 시스템이 에이전트를 서버에 심어 메트릭을 밀어냈다면(Push), 프로메테우스는 반대로 지정된 엔드포인트에 주기적으로 접속해 메트릭을 가져옵니다. 대상 서버는 /metrics 경로에 텍스트 형식의 데이터를 노출하기만 하면 됩니다.


이 방식의 장점은 명확합니다. 에이전트가 죽어도 스크레이프 자체가 실패하므로 장애를 감지할 수 있고, 수집 대상과 수집 주기를 프로메테우스 설정에서 중앙 관리할 수 있습니다. 단점은 방화벽이 엄격하거나 단기 실행 작업(배치 잡) 같은 수명이 짧은 대상은 수집이 어렵다는 점인데, 이를 위해 Pushgateway라는 보조 컴포넌트를 별도로 제공합니다.


저장소는 자체 내장 TSDB(시계열 데이터베이스)를 사용합니다. PromQL이라는 전용 쿼리 언어로 데이터를 조회하고 집계합니다. 기본 데이터 보존 기간은 15일이며, 장기 보존이 필요하면 Thanos나 Cortex 같은 외부 스토리지와 연동합니다.


Prometheus 스크레이프 아키텍처
프로메테우스 풀 방식 — 각 대상은 /metrics를 노출하고, 프로메테우스가 주기적으로 수집한다

Grafana란 무엇인가 — 단순한 시각화 툴을 넘어선 이유

그라파나는 데이터 시각화와 대시보드 플랫폼입니다. 프로메테우스만이 아니라 MySQL, PostgreSQL, Elasticsearch, InfluxDB, AWS CloudWatch 등 수십 가지 데이터소스를 동시에 연결할 수 있어, 분산된 시스템의 메트릭을 하나의 화면에서 볼 수 있습니다.


그라파나의 핵심 가치는 프리셋 대시보드 생태계에 있습니다. grafana.com/grafana/dashboards에는 수천 개의 검증된 대시보드가 공유되어 있습니다. Node Exporter Full(ID: 1860), Kubernetes Cluster(ID: 13770) 같은 대시보드는 JSON 한 번 가져오면 수백 개의 패널이 즉시 구성됩니다. 처음부터 만들 필요가 없습니다.


그라파나 10 이후 Scenes 기반 대시보드와 그라파나 Alloy(구 Grafana Agent)가 합류하면서 단순 시각화 툴을 넘어 전체 옵저버빌리티 플랫폼으로 확장되고 있습니다. 그라파나 클라우드를 쓰면 무료 플랜에서도 메트릭 1만 개, 3개월 보존이 제공됩니다. 하지만 이 글에서는 비용 0의 셀프 호스팅 방식을 사용합니다.


Docker Compose로 프로메테우스 + 그라파나 스택 구축

가장 빠르게 스택을 올리는 방법은 Docker Compose입니다. 서버에 도커가 설치되어 있다면 아래 파일 두 개로 5분 안에 동작하는 모니터링 환경이 만들어집니다. 먼저 디렉토리를 만들고 두 파일을 나란히 저장합니다.


docker-compose.yml
version: '3.8' services: prometheus: image: prom/prometheus:v2.52.0 container_name: prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - 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' restart: unless-stopped grafana: image: grafana/grafana:11.0.0 container_name: grafana volumes: - grafana_data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=강력한_비밀번호로_교체하세요 - GF_USERS_ALLOW_SIGN_UP=false ports: - '3000:3000' depends_on: - prometheus restart: unless-stopped node-exporter: image: prom/node-exporter:v1.8.1 container_name: node-exporter volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - '--path.procfs=/host/proc' - '--path.rootfs=/rootfs' - '--path.sysfs=/host/sys' - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($|/)' ports: - '9100:9100' restart: unless-stopped volumes: prometheus_data: grafana_data:
prometheus.yml
global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'node-exporter' static_configs: - targets: ['node-exporter:9100']

두 파일을 같은 디렉토리에 저장하고 docker compose up -d를 실행합니다. 기본 포트는 프로메테우스 9090, 그라파나 3000입니다. 브라우저에서 http://서버IP:9090으로 접속하면 프로메테우스 UI가, http://서버IP:3000으로 접속하면 그라파나 로그인 화면이 뜹니다.


GF_SECURITY_ADMIN_PASSWORD는 반드시 강력한 비밀번호로 교체해야 합니다. 기본값인 admin으로 두면 공개 서버에서 즉시 탈취됩니다. 16자 이상 랜덤 문자열로 교체하고, 가능하면 .env 파일로 분리해 docker-compose.yml에는 변수명만 남기는 것을 권장합니다.


포트 보안 주의: 기본 설정은 9090, 9100 포트가 외부에 열립니다. 프로덕션 서버라면 방화벽에서 9090·9100을 외부 접근 차단하고, Nginx 리버스 프록시 + HTTPS + 기본 인증(htpasswd)으로 접근을 제한하세요. 그라파나(3000)도 도메인 뒤로 숨기는 것이 안전합니다. 모니터링 도구 자체가 정보 유출 경로가 되는 사고가 실제로 자주 발생합니다.

Node Exporter 메트릭 확인과 주요 PromQL 쿼리

Node Exporter는 서버의 시스템 메트릭을 HTTP /metrics 엔드포인트로 노출하는 도구입니다. CPU 사용률, 메모리, 디스크 I/O, 네트워크 트래픽, 파일 디스크립터 수까지 수백 개의 지표를 자동으로 수집합니다.


스택이 올라간 후 http://서버IP:9090/targets에 접속하면 스크레이프 대상 상태를 확인할 수 있습니다. node-exporterUP이면 정상입니다. DOWN으로 표시되면 도커 네트워크 이름 해석 문제이거나 방화벽이 9100을 막고 있는 경우입니다.


자주 쓰는 PromQL 쿼리 몇 가지를 익혀두면 프로메테우스 UI에서 직접 빠른 진단이 가능합니다. 아래 쿼리를 프로메테우스 9090 포트 Graph 탭에 붙여넣기만 하면 바로 시각화됩니다.


PromQL — 자주 쓰는 핵심 쿼리
# CPU 사용률 (%) — idle 제외 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) # 메모리 사용률 (%) (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 # 디스크 사용률 (rootfs 기준) (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 # 네트워크 수신 속도 (eth0, bytes/s) rate(node_network_receive_bytes_total{device="eth0"}[5m]) # 열린 파일 디스크립터 수 node_filefd_allocated # 프로세스별 CPU (top 5) topk(5, rate(node_cpu_seconds_total{mode!="idle"}[5m]))
Prometheus 타깃 스크레이프 화면
프로메테우스 /targets 페이지 — 모든 항목이 UP이면 메트릭 수집 정상

애플리케이션 메트릭 노출하기 — Node.js prom-client 실전

서버 메트릭만으로는 부족합니다. API 응답 시간, 요청 수, 에러율 같은 애플리케이션 수준 메트릭을 함께 수집해야 진짜 모니터링이 됩니다. Node.js에서는 prom-client 라이브러리를 사용합니다.


패키지 설치
npm install prom-client
metrics.js — Express 애플리케이션에 메트릭 추가
const express = require('express'); const promClient = require('prom-client'); const app = express(); // 기본 메트릭 수집 활성화 (Node.js 프로세스 메트릭) promClient.collectDefaultMetrics({ timeout: 5000 }); // HTTP 요청 수 카운터 const httpRequestCounter = new promClient.Counter({ name: 'http_requests_total', help: '총 HTTP 요청 수', labelNames: ['method', 'route', 'status_code'] }); // 응답 시간 히스토그램 const httpRequestDuration = new promClient.Histogram({ name: 'http_request_duration_seconds', help: 'HTTP 요청 처리 시간 (초)', labelNames: ['method', 'route'], buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 2, 5] }); // 미들웨어 — 모든 요청에 메트릭 기록 app.use((req, res, next) => { const start = Date.now(); res.on('finish', () => { const duration = (Date.now() - start) / 1000; httpRequestCounter.labels(req.method, req.path, String(res.statusCode)).inc(); httpRequestDuration.labels(req.method, req.path).observe(duration); }); next(); }); // /metrics 엔드포인트 노출 app.get('/metrics', async (req, res) => { res.set('Content-Type', promClient.register.contentType); res.end(await promClient.register.metrics()); }); app.listen(3001, () => console.log('서버 시작: 3001'));

애플리케이션이 /metrics를 노출하면 prometheus.yml에 스크레이프 대상을 추가합니다. 도커 호스트에서 실행되는 앱이라면 host.docker.internal을 사용합니다.


prometheus.yml — 앱 메트릭 추가
scrape_configs: # ... 기존 설정 유지 ... - job_name: 'my-node-app' static_configs: - targets: ['host.docker.internal:3001'] # 도커 컨테이너 안에서 실행 중이라면: # targets: ['app-container-name:3001']

설정 변경 후 curl -X POST http://localhost:9090/-/reload를 호출하면 재시작 없이 설정을 즉시 반영할 수 있습니다. docker-compose.yml에 --web.enable-lifecycle 플래그가 포함되어 있어 가능한 방식입니다.


Grafana 대시보드 구성 — 데이터소스 연결과 프리셋 활용

그라파나에 처음 접속(http://서버IP:3000)하면 ID admin, 비밀번호는 docker-compose.yml에 설정한 값으로 로그인합니다. 첫 번째 할 일은 프로메테우스를 데이터소스로 추가하는 것입니다.


데이터소스 추가 경로: 좌측 메뉴 → Administration → Data sources → Add data source → Prometheus 선택 → URL에 http://prometheus:9090 입력(도커 컴포즈 내부 네트워크 이름 사용) → Save & test 클릭. 초록색 체크가 뜨면 연결 성공입니다.


데이터소스가 연결되면 검증된 프리셋 대시보드를 가져옵니다. 좌측 메뉴 → Dashboards → Import → 1860 입력 → Load → 데이터소스로 방금 추가한 프로메테우스 선택 → Import. 수십 개의 패널이 즉시 구성되어 CPU, 메모리, 디스크, 네트워크를 한 화면에서 볼 수 있습니다.


애플리케이션 메트릭용 커스텀 패널을 만들려면 새 대시보드에서 Add visualization을 클릭하고 PromQL을 직접 입력합니다.


그라파나 패널용 PromQL 예시
# API 에러율 (5xx 비율 %) rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100 # 99th percentile 응답 시간 (경로별) histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, route) ) # 초당 요청 수 (RPS, 경로별) sum(rate(http_requests_total[1m])) by (route) # 현재 활성 연결 수 node_sockstat_TCP_inuse
Grafana Node Exporter Full 대시보드
그라파나 Node Exporter Full(ID: 1860) — CPU·메모리·디스크·네트워크를 한 화면에서 확인

AlertManager로 슬랙 알림 설정 — 장애를 5분 안에 받는 법

대시보드를 24시간 들여다볼 수는 없습니다. 임계치를 넘으면 자동으로 알림을 보내는 AlertManager가 필요합니다. docker-compose.yml에 AlertManager 서비스를 추가하고 설정 파일을 작성합니다.


docker-compose.yml — alertmanager 서비스 추가
alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml ports: - '9093:9093' restart: unless-stopped
alertmanager.yml — 슬랙 연동 설정
global: resolve_timeout: 5m route: receiver: 'slack-notifications' group_wait: 30s group_interval: 5m repeat_interval: 4h receivers: - name: 'slack-notifications' slack_configs: - api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK' channel: '#alerts' title: '{{ .GroupLabels.alertname }}' text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}' send_resolved: true
prometheus.yml — 알림 설정 추가
global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: ['alertmanager:9093'] rule_files: - 'alerts.yml' scrape_configs: # ... 기존 스크레이프 설정 ...
alerts.yml — 알림 규칙 예시
groups: - name: server-alerts rules: - alert: HighCPUUsage expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85 for: 5m labels: severity: warning annotations: summary: 'CPU 사용률 85% 초과' - alert: HighMemoryUsage expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90 for: 2m labels: severity: critical annotations: summary: '메모리 사용률 90% 초과 — 즉시 확인 필요' - alert: DiskSpaceLow expr: (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 > 85 for: 10m labels: severity: warning annotations: summary: '루트 디스크 사용률 85% 초과' - alert: HighErrorRate expr: rate(http_requests_total{status_code=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05 for: 1m labels: severity: critical annotations: summary: 'API 에러율 5% 초과 — 서비스 이상 확인 필요'
슬랙 Webhook URL 발급 방법: Slack 앱 관리 페이지(api.slack.com/apps) → Create New App → From scratch → Incoming Webhooks 활성화 → Add New Webhook to Workspace → 채널 선택 → Webhook URL 복사. 발급된 URL은 절대 Git에 커밋하지 마세요. .env 파일 또는 시크릿 관리 시스템으로 주입하는 것이 안전합니다.

프로덕션 운영 팁 — 데이터 보존, 고가용성, 리소스 관리

스택을 올렸다면 장기 운영을 위한 설정을 점검합니다. 아래 항목들은 처음 셋업 후 놓치기 쉬운 부분입니다.


데이터 보존 기간: 기본값은 15일입니다. docker-compose.yml의 --storage.tsdb.retention.time=30d를 원하는 값으로 조정합니다. 용량 기반으로도 설정할 수 있습니다. --storage.tsdb.retention.size=20GB로 지정하면 20GB 초과 시 오래된 데이터부터 삭제합니다. 두 옵션을 동시에 지정하면 먼저 도달한 기준으로 정리됩니다. 참고로 서버 10대의 30일치 메트릭은 보통 2~8GB 수준입니다.


그라파나 대시보드 백업: 볼륨이 삭제되면 대시보드 설정도 사라집니다. 그라파나 HTTP API를 활용해 대시보드를 JSON으로 내보내 Git에 저장하는 것을 권장합니다. 또는 그라파나 Provisioning 기능을 사용해 파일 기반으로 대시보드를 관리하면, 볼륨이 초기화되어도 컨테이너 재시작 시 자동 복원됩니다.


장기 스토리지: 90일 이상 보존이 필요하다면 Thanos를 사이드카로 추가해 S3 같은 오브젝트 스토리지에 데이터를 아카이브하는 방식이 표준입니다. Thanos Query로 여러 프로메테우스 인스턴스의 데이터를 통합 쿼리할 수도 있어, 대규모 환경에서 선호됩니다.


고가용성: 단일 프로메테우스 인스턴스는 재시작 시 수집 공백이 생깁니다. 동일한 설정의 프로메테우스 두 대를 병렬로 운영하고 그라파나에서 두 인스턴스를 모두 데이터소스로 등록하면 기본적인 이중화가 됩니다.


리소스 사용량: 스크레이프 대상 10개 이하, 보존 30일 기준으로 프로메테우스는 1~2GB RAM, 그라파나는 256~512MB RAM으로 충분합니다. 2 vCPU, 4GB RAM VPS에서도 문제없이 운영됩니다.


참고 자료


자주 묻는 질문

Q. 프로메테우스와 그라파나를 꼭 함께 써야 하나요?

반드시 함께 쓸 필요는 없습니다. 프로메테우스 자체 UI(9090 포트)에서도 PromQL로 메트릭을 조회하고 그래프를 볼 수 있습니다. 하지만 팀 공유 대시보드, 알림 설정 UI, 멀티 데이터소스 통합이 필요하다면 그라파나가 사실상 필수입니다. 대부분의 실무 환경에서는 두 도구를 함께 사용합니다.


Q. 그라파나 클라우드 무료 플랜 vs 셀프 호스팅 — 어떤 걸 선택해야 하나요?

트래픽이 적고(메트릭 1만 개 이하) 데이터 보존 3개월로 충분하다면 그라파나 클라우드 무료 플랜이 편합니다. 서버 관리 부담이 없고, 기본 알림 기능도 제공됩니다. 반면 메트릭 수가 많거나(1만 개 초과 시 과금), 데이터를 외부로 보내기 싫거나, 장기 보존이 필요하다면 셀프 호스팅이 유리합니다. 개인 서버 1~2대를 운영하는 소규모라면 셀프 호스팅 추가 비용은 거의 0에 가깝습니다.


Q. 쿠버네티스 환경에서는 설치 방법이 다른가요?

쿠버네티스에서는 Helm Chart kube-prometheus-stack(구 prometheus-operator)을 사용합니다. helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack 한 줄로 프로메테우스, 그라파나, kube-state-metrics, Node Exporter가 모두 배포됩니다. 쿠버네티스 메트릭(파드, 노드, 디플로이먼트 상태)도 자동 수집됩니다. 이 글에서 다룬 Docker Compose 방식은 베어메탈이나 단일 VM 환경에 적합합니다.


Q. 프로메테우스 스크레이프 주기를 얼마로 설정하는 게 좋나요?

기본값 15초가 대부분의 경우 적합합니다. 단기 스파이크를 놓치지 않으려면 5~10초로 줄일 수 있지만, 데이터 양이 3배 늘어나고 스토리지 부담이 커집니다. 반대로 보존 기간이 길고 디스크가 부족하면 30~60초로 늘려도 됩니다. 단, 알림 규칙의 for: 기간은 스크레이프 주기보다 2~3배 길게 설정해야 합니다. 15초 주기면 for: 1m 이상을 사용하세요.


Q. AlertManager 없이 그라파나만으로 알림을 보낼 수 있나요?

가능합니다. 그라파나 Alerting 기능에서 슬랙, 이메일, PagerDuty 등으로 직접 알림을 보낼 수 있습니다. 알림 조건을 PromQL로 작성하고 Contact point에 슬랙 Webhook을 등록하면 됩니다. AlertManager가 별도로 필요한 경우는 알림 그룹핑과 중복 제거가 복잡하거나, 여러 프로메테우스 인스턴스에서 알림을 중앙 관리해야 할 때입니다. 소규모 개인 서버라면 그라파나 자체 Alerting만으로 충분합니다.


Q. Node Exporter 말고 다른 Exporter는 어떤 게 있나요?

용도별로 다양한 공식 Exporter가 있습니다. 데이터베이스: postgres_exporter(PostgreSQL), mysqld_exporter(MySQL), redis_exporter(Redis). 웹 서버: nginx-prometheus-exporter, apache_exporter. 클라우드: cloudwatch_exporter(AWS), stackdriver_exporter(GCP). 애플리케이션: jmx_exporter(Java/JVM), blackbox_exporter(HTTP·TCP 헬스체크). 각 Exporter는 Docker Compose에 서비스로 추가하고 prometheus.yml에 스크레이프 대상으로 등록하면 됩니다. 공식 목록은 prometheus.io/docs/instrumenting/exporters/에서 확인할 수 있습니다.


PrometheusGrafanaDockerNode Exporter서버 모니터링AlertManager오픈소스옵저버빌리티DevOpsprom-client

관련 도구

함께 보면 좋은 문제 해결

EXPLORE / Open Source

이어서 읽어보기

전체 토픽 둘러보기