
내 서버 상태, 눈으로 바로 확인할 수 있다면?
홈서버나 NAS를 운영하다 보면 문득 궁금해질 때가 있습니다. 지금 CPU는 얼마나 쓰고 있는 걸까? 메모리는 괜찮은가? 디스크가 슬슬 부족하진 않나? SSH로 접속해서 htop을 실행하거나 df -h를 입력하면 확인할 수 있지만, 매번 터미널을 열기엔 번거롭습니다. 더 큰 문제는 ‘과거 데이터’입니다. 지금 이 순간의 CPU 사용률은 확인할 수 있어도, 어제 새벽 3시에 갑자기 CPU가 100%를 찍었는지는 알 수 없죠.
이런 고민을 한 방에 해결해주는 조합이 바로 Grafana + Prometheus + Node Exporter입니다. 이 세 가지를 Docker로 설치하면, 웹 브라우저에서 예쁜 대시보드로 서버 상태를 실시간으로 확인할 수 있습니다. 과거 이력도 자동으로 저장되고, 디스크 사용률이 90%를 넘으면 텔레그램이나 이메일로 알림까지 보내줍니다. 이 글에서는 리눅스 기본 지식만 있으면 누구든 따라 할 수 있도록 처음부터 끝까지 상세하게 안내합니다.

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 정도의 디스크 공간을 사용합니다.

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_data와grafana_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를 데이터 소스로 등록해야 합니다.
- 왼쪽 사이드바에서 톱니바퀴(⚙️) → Data Sources를 클릭합니다.
- Add data source 버튼을 클릭합니다.
- 목록에서 Prometheus를 선택합니다.
- Connection 섹션의 Prometheus server URL에
http://prometheus:9090을 입력합니다. (Docker 내부 네트워크 이름을 사용합니다.) - 나머지 설정은 기본값 그대로 두고 페이지 하단의 Save & Test를 클릭합니다.
- “Successfully queried the Prometheus API.” 메시지가 나오면 연결 성공입니다.
여기서 URL에 localhost가 아닌 prometheus를 사용하는 이유가 중요합니다. Grafana 컨테이너 입장에서 localhost는 자기 자신(Grafana 컨테이너)을 가리킵니다. Docker Compose의 같은 네트워크 안에 있는 Prometheus 컨테이너에 접근하려면 서비스 이름인 ‘prometheus’를 사용해야 합니다.
6단계: Node Exporter 대시보드 가져오기
Grafana의 진짜 강점은 커뮤니티 대시보드입니다. 직접 그래프를 하나하나 만들 필요 없이, 전문가들이 이미 만들어 놓은 완성도 높은 대시보드를 ID 하나로 가져올 수 있습니다.
- 왼쪽 사이드바에서 + → Import dashboard를 클릭합니다.
- Import via grafana.com 입력란에 1860을 입력하고 Load를 클릭합니다.
- 하단의 Prometheus 데이터 소스 드롭다운에서 방금 추가한 Prometheus를 선택합니다.
- Import를 클릭합니다.
짜잔! 순식간에 완성도 높은 모니터링 대시보드가 나타납니다. 1860번 대시보드는 “Node Exporter Full”이라는 이름으로, 가장 인기 있는 Node Exporter 대시보드입니다. 다운로드 수가 수천만 건에 달하며, CPU·메모리·디스크·네트워크를 한 화면에서 종합적으로 볼 수 있습니다.

대시보드 상단에서 시간 범위를 조절할 수 있습니다. 기본은 최근 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를 설정해야 합니다.
- 왼쪽 사이드바에서 Alerting → Contact points로 이동합니다.
- + Add contact point를 클릭합니다.
- Name에 “Telegram”을 입력합니다.
- Integration 드롭다운에서 Telegram을 선택합니다.
- BOT API Token에 텔레그램 봇 토큰을 입력합니다.
- Chat ID에 알림을 받을 채팅방 ID를 입력합니다.
- Test 버튼으로 테스트 메시지를 보내보고, Save contact point를 클릭합니다.
텔레그램 봇이 없다면 @BotFather에게 메시지를 보내 새 봇을 만들 수 있습니다. Chat ID는 @userinfobot에게 메시지를 보내면 확인할 수 있습니다.
디스크 사용률 90% 초과 알림 규칙 만들기
- Alerting → Alert rules로 이동합니다.
- + New alert rule을 클릭합니다.
- Rule name에 “디스크 사용률 경고”를 입력합니다.
- 쿼리 섹션에서 데이터 소스를 Prometheus로 선택하고, 다음 쿼리를 입력합니다:
(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100
- Expressions 섹션에서 Threshold 조건을 IS ABOVE 90으로 설정합니다.
- Evaluation behavior에서 폴더를 선택하고, Evaluation group을 설정합니다. Pending period는 “5m”으로 설정합니다(5분간 지속될 때만 알림 발생).
- Labels and notifications에서 Contact point를 앞서 만든 “Telegram”으로 지정합니다.
- Save rule and exit를 클릭합니다.
Pending period를 5분으로 설정하는 이유가 중요합니다. 일시적인 스파이크로 인한 오탐(false positive)을 방지하기 위해서입니다. 디스크 사용률이 90%를 넘는 상태가 5분간 지속되어야만 실제 알림이 발생합니다.
자주 쓰는 알림 규칙 예시
- CPU 사용률 85% 초과 (5분 지속): 서버 과부하 감지
- 메모리 사용률 90% 초과 (5분 지속): 메모리 부족 경고
- 디스크 사용률 90% 초과: 디스크 정리 필요 알림
- 서버 다운 감지:
up{job="node"} == 0쿼리로 Node Exporter 응답 없음 감지 - 네트워크 트래픽 급증: 평소 대비 비정상적 트래픽 감지

실전 팁: 운영하면서 알게 된 것들
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 로 생성되었습니다.