Prometheus와 Grafana 완벽 가이드: Docker로 구축하는 서버 성능 모니터링 시스템

이전 포스팅에서 다룬 ELK Stack이 “과거에 무슨 일이 있었는지(Logs)“를 분석하는 도구라면, 오늘 다룰 Prometheus와 Grafana는 “현재 서버의 상태가 어떤지(Metrics)“를 진단하는 청진기와 같습니다.


Prometheus와 Grafana 완벽 가이드: Docker로 구축하는 서버 성능 모니터링 시스템

1. 서론

지난 시간에 우리는 ELK Stack을 통해 대용량 로그를 통합 관리하는 방법을 배웠습니다. 이제 여러분은 특정 에러가 언제 발생했는지 로그를 통해 추적할 수 있는 능력을 갖추게 되었습니다. 하지만 로그만으로는 시스템의 전체적인 건강 상태를 파악하는 데 한계가 존재합니다. 예를 들어, 서버가 느려졌다는 제보가 들어왔을 때 로그 파일에는 아무런 에러도 찍혀있지 않을 수 있습니다. 단순히 CPU 사용량이 100%를 찍었거나, 메모리 누수(Memory Leak)로 인해 가용 램이 부족해져서 스왑(Swap)이 발생하고 있을 수도 있기 때문입니다.

이처럼 로그(Log)가 ‘발생한 사건’에 대한 기록이라면, **메트릭(Metric)**은 ‘시스템의 상태’를 나타내는 수치 데이터입니다. “현재 CPU 점유율은 몇 %인가?”, “남은 디스크 용량은 얼마인가?”, “초당 들어오는 요청 수(RPS)는 몇 건인가?”와 같은 질문에 답하기 위해서는 로그가 아닌 메트릭을 수집하고 시각화해야 합니다. 그리고 이 분야에서 사실상의 표준(De Facto Standard)으로 자리 잡은 오픈소스 조합이 바로 **Prometheus(프로메테우스)**와 **Grafana(그라파나)**입니다. 오늘은 이 두 도구가 왜 강력한지, 그리고 어떻게 구축하여 내 서버의 상태를 한눈에 파악할 수 있는지 깊이 있게 알아보겠습니다.


2. 본론

1: 왜 Prometheus인가? (Pull 방식과 TSDB의 혁명)

모니터링 도구는 춘추전국시대라고 할 만큼 종류가 다양합니다. Zabbix, Nagios, Datadog 등 쟁쟁한 경쟁자들 사이에서 Prometheus가 클라우드 네이티브 환경의 표준이 된 이유는 명확합니다.

첫째, 시계열 데이터베이스(TSDB, Time-Series Database)에 최적화되어 있습니다. 서버 모니터링 데이터는 ‘시간’과 ‘수치’로 이루어진 데이터가 1초에도 수천, 수만 건씩 쏟아지는 특성을 가집니다. 일반적인 관계형 데이터베이스(RDBMS)인 MySQL이나 PostgreSQL은 이런 데이터를 처리하기에 구조적으로 무겁고 느립니다. Prometheus는 오직 이런 시계열 데이터를 저장하고 검색하는 데 특화된 자체 엔진을 사용하여, 놀라운 압축률과 검색 속도를 제공합니다.

둘째, 독특한 Pull 방식의 아키텍처를 채택했습니다. 기존의 많은 모니터링 도구들은 에이전트가 중앙 서버로 데이터를 밀어 넣는 ‘Push 방식’을 사용했습니다. 이 경우 모니터링 대상이 늘어날수록 중앙 서버에 부하가 집중되어 병목이 발생할 위험이 큽니다. 반면, Prometheus는 중앙 서버가 주기적으로 대상 서버들에 접속하여 데이터를 긁어오는(Scraping) ‘Pull 방식’을 사용합니다. 이를 통해 중앙 서버는 자신의 처리 능력에 맞춰 수집 주기를 조절할 수 있어 과부하를 방지할 수 있으며, 장애 발생 시 어떤 서버가 응답하지 않는지 즉각적으로 파악할 수 있는 이점도 가집니다.

2: 모니터링 시스템의 핵심 아키텍처 (Exporter, Prometheus, Grafana)

Prometheus 생태계는 크게 세 가지 구성 요소로 이루어집니다. 이들의 유기적인 연결 관계를 이해하는 것이 구축의 첫걸음입니다.

  1. Exporter (데이터 수집원):Prometheus는 스스로 데이터를 생성하지 않습니다. 대신 데이터를 수집해서 HTTP 엔드포인트(/metrics)로 노출해 주는 대리인이 필요한데, 이를 ‘Exporter’라고 부릅니다. 서버의 CPU, 메모리, 디스크 정보를 수집하는 Node Exporter, MySQL DB 정보를 수집하는 MySQL Exporter 등 모니터링 대상에 맞는 Exporter를 설치해야 합니다.
  2. Prometheus Server (데이터 저장 및 쿼리):정해진 주기(예: 15초)마다 등록된 Exporter들의 URL에 접속하여 메트릭 데이터를 긁어와(Scraping) 자신의 로컬 스토리지에 저장합니다. 그리고 사용자가 데이터를 조회할 수 있도록 PromQL(Prometheus Query Language)이라는 강력한 쿼리 언어를 제공합니다.
  3. Grafana (데이터 시각화):Prometheus 자체적으로도 간단한 그래프 기능을 제공하지만, 운영용 대시보드로 쓰기에는 부족함이 많습니다. Grafana는 Prometheus를 포함한 다양한 데이터 소스(DB)에 연결하여 화려하고 직관적인 대시보드를 만들어주는 시각화 도구입니다. “CPU 사용량이 80%를 넘으면 빨간색으로 표시하라”와 같은 임계값 설정이나 알림 연동이 가능하여 관제 시스템의 모니터(View) 역할을 완벽하게 수행합니다.

3: Docker Compose를 활용한 모니터링 시스템 구축 실습

이제 이론을 바탕으로 실제 서버에 모니터링 시스템을 구축해 보겠습니다. 여러 개의 컨테이너를 한 번에 관리하기 위해 이번에도 Docker Compose를 사용합니다.

먼저, 프로젝트 폴더 구조를 생성하고 설정 파일들을 준비합니다. 가장 중요한 것은 Prometheus가 어떤 Exporter를 바라볼지 정의하는 prometheus.yml 설정 파일입니다.

1. prometheus.yml 작성

프로젝트 루트에 prometheus 폴더를 만들고 그 안에 prometheus.yml을 생성합니다.

YAML

global:
  scrape_interval: 15s # 15초마다 메트릭을 수집 (기본값)
  evaluation_interval: 15s

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

  # 2. Node Exporter (호스트 서버 모니터링)
  - job_name: 'node_exporter'
    static_configs:
      - targets: ['node-exporter:9100'] # 컨테이너 서비스명 사용

2. docker-compose.yml 작성

프로젝트 루트에 docker-compose.yml 파일을 생성합니다. 여기서는 Prometheus, Grafana, 그리고 서버의 리소스를 수집할 Node Exporter를 함께 띄웁니다.

YAML

version: '3.8'

services:
  # 1. Prometheus: 메트릭 수집 및 저장
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    ports:
      - "9090:9090"
    depends_on:
      - node-exporter

  # 2. Node Exporter: 호스트 시스템의 메트릭 추출
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    # 호스트의 실제 /proc, /sys 파일시스템에 접근 권한 부여
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points'
      - '^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)'

  # 3. Grafana: 시각화 대시보드
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus

volumes:
  prometheus_data:
  grafana_data:

이제 docker-compose up -d 명령어를 입력하면 3개의 컨테이너가 실행됩니다. 웹 브라우저에서 localhost:3000으로 접속하여 Grafana에 로그인(admin/admin)할 수 있습니다.

4: Grafana 대시보드 연동 및 시각화

Grafana가 실행되었다고 해서 바로 그래프가 보이는 것은 아닙니다. 데이터 소스를 연결하고 대시보드를 구성해야 합니다.

  1. 데이터 소스(Data Source) 추가:Grafana 왼쪽 메뉴의 설정(톱니바퀴) -> Data Sources -> Add data source를 클릭합니다. ‘Prometheus’를 선택하고 URL 입력창에 http://prometheus:9090을 입력합니다. (Docker 네트워크 내부 통신이므로 컨테이너 이름을 사용합니다.) ‘Save & Test’를 눌러 연결 성공 메시지를 확인합니다.
  2. 대시보드 가져오기 (Import):일일이 그래프를 만들 필요가 없습니다. 전 세계 개발자들이 이미 만들어둔 훌륭한 템플릿을 가져다 쓰면 됩니다. 왼쪽 메뉴의 ‘+’ 버튼 -> Import를 클릭합니다. ‘Import via grafana.com’ 입력창에 ‘1860‘이라는 숫자를 입력하고 Load를 누릅니다. 이 ID는 ‘Node Exporter Full’이라는 매우 유명한 대시보드 템플릿입니다. 데이터 소스로 방금 등록한 Prometheus를 선택하고 Import를 완료하면, 순식간에 내 서버의 CPU, 메모리, 디스크 I/O, 네트워크 트래픽 등이 화려한 그래프로 펼쳐지는 것을 볼 수 있습니다.

5: 실무 운영 팁과 확장성

Prometheus를 운영 환경에 도입할 때 몇 가지 고려해야 할 사항이 있습니다. 우선 데이터 보관 주기입니다. Prometheus는 로컬 디스크에 데이터를 저장하므로, 무한정 데이터를 쌓을 수 없습니다. 기본 설정은 15일 보관입니다. 만약 1년 치 데이터를 보관해야 한다면 Thanos나 Cortex 같은 장기 보관소(Long-term Storage) 솔루션을 추가로 연동해야 합니다.

또한, 알림(Alerting) 설정이 필수적입니다. Grafana 자체의 Alert 기능을 사용하거나, Prometheus의 형제 격인 Alertmanager를 별도로 띄워서 사용할 수 있습니다. “CPU 사용량이 5분 동안 90% 이상 유지될 때 슬랙으로 메시지 전송”과 같은 규칙을 설정해 두면, 모니터를 계속 보고 있지 않아도 장애 징후를 조기에 파악할 수 있습니다.


3. 결론

지금까지 Prometheus와 Grafana를 활용하여 서버의 성능 지표를 실시간으로 모니터링하는 시스템을 구축해 보았습니다.

이전에 다루었던 ELK Stack이 ‘로그 분석‘을 통해 “왜 에러가 났는가?”를 밝혀내는 현미경이라면, 오늘 구축한 모니터링 시스템은 ‘메트릭 분석‘을 통해 “지금 시스템이 얼마나 아픈가?”를 진단하는 체온계이자 심박 측정기입니다. 진정한 의미의 관측 가능성(Observability)은 이 두 가지 시스템이 조화롭게 갖춰졌을 때 비로소 완성됩니다.

이제 여러분은 서버가 보내는 신호를 놓치지 않고 포착할 수 있는 강력한 눈을 갖게 되었습니다. 단순히 그래프를 감상하는 것을 넘어, 평소의 리소스 사용 패턴을 분석하여 적절한 서버 증설 시기를 예측하고, 잠재적인 병목 구간을 찾아내어 튜닝하는 엔지니어링의 영역으로 나아가시기를 바랍니다. 안정적인 서비스 운영은 철저한 모니터링에서부터 시작된다는 사실을 잊지 마시기 바랍니다.


로그와 메트릭을 정복했다면, 마지막 관문인 ‘추적(Tracing)‘이 남았습니다. MSA 환경에서 요청이 여러 마이크로서비스를 거쳐갈 때 병목 구간을 시각화해 주는 “Spring Boot에 Jaeger를 연동하여 분산 추적(Distributed Tracing) 시스템 구축하기“에 대해 포스팅을 이어가 볼까요?

댓글 남기기