<scshin />

Prometheus, Grafana, Node Exporter 모니터링 환경 구축

0.86

Podman Compose로 Prometheus, Grafana, Node Exporter 모니터링 환경 구축하기

서버를 운영하다 보면 다음과 같은 정보를 계속 확인해야 합니다.

  • CPU 사용률이 갑자기 높아지지 않았는지
  • 메모리가 부족하지 않은지
  • 디스크 용량이 가득 차지 않았는지
  • 네트워크 송수신량이 비정상적으로 증가하지 않았는지
  • 모니터링 대상 서버가 정상적으로 살아 있는지

명령어로 서버에 접속하여 top, free, df, ss 등을 실행하면 현재 상태를 확인할 수 있습니다. 하지만 과거 사용량 변화와 장애 발생 시점을 확인하거나 여러 서버를 한 화면에서 관리하기에는 불편합니다.

이때 많이 사용하는 조합이 다음 세 가지입니다.

  • Node Exporter: 리눅스 서버의 시스템 상태를 수집 가능한 형태로 제공
  • Prometheus: Node Exporter의 메트릭을 주기적으로 수집하고 저장
  • Grafana: Prometheus에 저장된 메트릭을 대시보드와 그래프로 시각화

이번 글에서는 Podman Compose를 사용하여 세 서비스를 한 번에 구성하고, 리눅스 서버의 CPU, 메모리, 디스크 및 네트워크 상태를 확인하는 방법을 정리합니다.


1. 전체 구성 이해하기

전체 흐름은 다음과 같습니다.

┌──────────────────────────────────────────┐
│ 리눅스 호스트 서버                       │
│                                          │
│  Node Exporter                           │
│  └─ CPU, 메모리, 디스크, 네트워크 메트릭 │
└───────────────────┬──────────────────────┘
                    │ 9100/metrics 수집
                    ▼
┌──────────────────────────────────────────┐
│ Prometheus                               │
│ └─ 메트릭 주기적 수집 및 시계열 저장     │
└───────────────────┬──────────────────────┘
                    │ PromQL 조회
                    ▼
┌──────────────────────────────────────────┐
│ Grafana                                  │
│ └─ 차트, 게이지, 표, 대시보드 시각화      │
└──────────────────────────────────────────┘

각 서비스의 기본 포트는 다음과 같습니다.

서비스 기본 포트 역할
Node Exporter 9100 리눅스 호스트 메트릭 제공
Prometheus 9090 메트릭 수집, 저장 및 조회
Grafana 3000 메트릭 시각화 및 대시보드 구성

2. Prometheus, Grafana, Node Exporter 역할

2.1 Node Exporter

Node Exporter는 리눅스 서버의 운영체제 및 하드웨어 관련 메트릭을 /metrics 형식으로 제공합니다.

대표적으로 다음 항목을 수집할 수 있습니다.

  • CPU 사용 시간과 Load Average
  • 전체 메모리와 사용 가능 메모리
  • Swap 사용량
  • 파일 시스템 전체 용량과 여유 공간
  • 디스크 읽기 및 쓰기
  • 네트워크 송수신량
  • 네트워크 오류 및 드롭 패킷
  • 서버 부팅 시간
  • 파일 디스크립터와 커널 관련 정보

Node Exporter 자체가 데이터를 장기간 저장하는 것은 아닙니다. 현재 시스템 상태를 Prometheus가 읽을 수 있는 형태로 노출하는 역할을 합니다.

2.2 Prometheus

Prometheus는 Node Exporter의 /metrics 주소에 일정한 간격으로 접속하여 메트릭을 가져옵니다.

수집한 데이터는 시간 정보와 함께 저장되므로 다음과 같은 분석이 가능합니다.

  • 최근 5분간 CPU 평균 사용률
  • 지난 24시간 메모리 사용량 변화
  • 일주일 동안 디스크 사용량 증가 추세
  • 특정 시점에 서버가 응답하지 않았는지 확인
  • 네트워크 트래픽 급증 시점 확인

Prometheus 데이터는 PromQL이라는 전용 쿼리 언어로 조회합니다.

2.3 Grafana

Grafana는 Prometheus를 데이터 소스로 연결하여 수집된 데이터를 시각화합니다.

다음과 같은 형태로 표현할 수 있습니다.

  • CPU 사용률 선 그래프
  • 메모리 사용률 게이지
  • 디스크 사용률 표
  • 네트워크 송수신량 차트
  • 서버 정상 여부 상태 패널
  • 임계치 초과 알림

즉, Node Exporter가 측정값을 제공하고, Prometheus가 저장하며, Grafana가 화면으로 보여주는 구조입니다.


3. 디렉터리 구성

작업할 디렉터리를 생성합니다.

mkdir -p monitoring
cd monitoring

최종 디렉터리 구조는 다음과 같습니다.

monitoring/
├── docker-compose.yml
└── prometheus.yml

Podman Compose 환경에 따라 파일명을 compose.yml 또는 compose.yaml로 사용해도 됩니다.


4. Docker Compose 파일 작성

docker-compose.yml 파일을 생성합니다.

version: '3.8'

services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: always
    network_mode: "host"
    pid: "host"
    volumes:
      - /:/host:ro,rslave
    command:
      - '--path.rootfs=/host'

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:Z
      - prometheus-data:/prometheus

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana:Z

volumes:
  prometheus-data:
  grafana-data:

최신 Docker Compose에서는 최상단의 version 항목이 사실상 필요하지 않습니다. 기존 Compose 및 Podman Compose 환경과의 호환성을 고려하여 그대로 사용할 수 있으며, 경고가 표시되는 경우 version: '3.8' 줄만 제거해도 됩니다.


5. Compose 설정 상세 설명

5.1 Node Exporter 설정

node-exporter:
  image: prom/node-exporter:latest
  container_name: node-exporter
  restart: always
  network_mode: "host"
  pid: "host"
  volumes:
    - /:/host:ro,rslave
  command:
    - '--path.rootfs=/host'

network_mode: "host"

Node Exporter가 컨테이너의 네트워크가 아니라 호스트의 네트워크 환경을 기준으로 동작하도록 설정합니다.

이 설정을 사용하면 별도의 다음 포트 매핑은 필요하지 않습니다.

ports:
  - "9100:9100"

Node Exporter는 호스트의 9100 포트에서 직접 실행됩니다.

pid: "host"

Node Exporter가 호스트의 PID 네임스페이스를 사용하도록 설정합니다. 컨테이너 내부 프로세스가 아니라 호스트 시스템 기준으로 일부 정보를 확인하기 위한 설정입니다.

/:/host:ro,rslave

호스트의 루트 파일 시스템 /을 컨테이너의 /host에 읽기 전용으로 연결합니다.

옵션의 의미는 다음과 같습니다.

  • ro: 읽기 전용 마운트
  • rslave: 호스트의 하위 마운트 변경 사항을 컨테이너에서도 확인

Node Exporter는 호스트 시스템을 모니터링해야 하므로 컨테이너 내부 파일 시스템이 아닌 실제 호스트 파일 시스템을 참조해야 합니다.

/ 전체를 마운트하는 항목에는 :Z를 추가하지 않는 것이 좋습니다. 시스템 전체 디렉터리에 SELinux 재라벨링을 적용하면 다른 서비스에 영향을 줄 수 있습니다.

--path.rootfs=/host

Node Exporter가 /host를 호스트의 루트 파일 시스템으로 인식하도록 지정합니다.

이 옵션이 없으면 Node Exporter가 호스트가 아닌 컨테이너 파일 시스템을 기준으로 일부 메트릭을 수집할 수 있습니다.


5.2 Prometheus 설정

prometheus:
  image: prom/prometheus:latest
  container_name: prometheus
  restart: always
  ports:
    - "9090:9090"
  volumes:
    - ./prometheus.yml:/etc/prometheus/prometheus.yml:Z
    - prometheus-data:/prometheus

9090:9090

호스트의 9090 포트를 Prometheus 컨테이너의 9090 포트에 연결합니다.

브라우저에서는 다음 주소로 접속합니다.

http://서버-IP:9090

prometheus.yml 마운트

- ./prometheus.yml:/etc/prometheus/prometheus.yml:Z

현재 디렉터리의 prometheus.yml 파일을 컨테이너 내부의 Prometheus 설정 파일 위치에 연결합니다.

Podman과 SELinux를 사용하는 환경에서는 :Z 옵션으로 해당 파일을 현재 컨테이너가 접근할 수 있도록 재라벨링합니다.

Prometheus 데이터 볼륨

- prometheus-data:/prometheus

Prometheus가 수집한 시계열 데이터를 Named Volume에 저장합니다.

이 볼륨이 없으면 컨테이너 삭제 후 기존 모니터링 데이터가 함께 사라질 수 있습니다.


5.3 Grafana 설정

grafana:
  image: grafana/grafana:latest
  container_name: grafana
  restart: always
  ports:
    - "3000:3000"
  volumes:
    - grafana-data:/var/lib/grafana:Z

3000:3000

호스트의 3000 포트를 Grafana 컨테이너의 3000 포트에 연결합니다.

브라우저에서는 다음 주소로 접속합니다.

http://서버-IP:3000

Grafana 데이터 볼륨

- grafana-data:/var/lib/grafana:Z

Grafana는 다음 정보를 /var/lib/grafana에 저장합니다.

  • 사용자 계정
  • 데이터 소스 설정
  • 대시보드
  • 폴더
  • 알림 설정
  • 플러그인 및 내부 데이터

Named Volume을 연결하면 컨테이너를 다시 생성해도 설정과 대시보드가 유지됩니다.


6. Prometheus 수집 설정 작성

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:
          - "host.containers.internal:9100"

scrape_interval

scrape_interval: 15s

Prometheus가 각 모니터링 대상에서 메트릭을 가져오는 기본 주기입니다.

위 설정에서는 15초마다 Node Exporter의 메트릭을 수집합니다.

Prometheus 자체 모니터링

- job_name: "prometheus"
  static_configs:
    - targets:
        - "localhost:9090"

Prometheus가 자기 자신의 상태를 수집합니다.

이때 localhost:9090은 Prometheus 컨테이너 내부의 Prometheus 자신을 의미하므로 사용할 수 있습니다.

Node Exporter 모니터링

- job_name: "node-exporter"
  static_configs:
    - targets:
        - "host.containers.internal:9100"

Node Exporter는 network_mode: host로 실행되고, Prometheus는 기본 컨테이너 네트워크에서 실행됩니다.

따라서 Prometheus 설정에서 다음과 같이 작성하면 안 됩니다.

targets:
  - "localhost:9100"

Prometheus 컨테이너에서 localhost는 호스트 서버가 아니라 Prometheus 컨테이너 자신을 가리키기 때문입니다.

Podman은 일반적으로 컨테이너에서 호스트로 접근할 수 있도록 다음 호스트명을 제공합니다.

host.containers.internal

환경에 따라 이 이름이 동작하지 않는 경우에는 호스트 서버의 실제 IP를 사용합니다.

- job_name: "node-exporter"
  static_configs:
    - targets:
        - "192.168.0.10:9100"

192.168.0.10 부분은 실제 서버 IP로 변경해야 합니다.


7. 컨테이너 실행

Compose 파일이 있는 디렉터리에서 실행합니다.

podman compose up -d

환경에 따라 다음 명령어를 사용해야 할 수도 있습니다.

podman-compose up -d

-d 옵션은 컨테이너를 백그라운드에서 실행한다는 의미입니다.

실행 상태를 확인합니다.

podman ps

정상적으로 실행되면 다음 세 컨테이너가 표시됩니다.

node-exporter
prometheus
grafana


8. Node Exporter 확인

서버에서 Node Exporter 메트릭 주소를 확인합니다.

curl http://127.0.0.1:9100/metrics

정상이라면 다음과 같은 메트릭이 출력됩니다.

node_cpu_seconds_total{cpu="0",mode="idle"} 12345.67
node_memory_MemTotal_bytes 1.6651070464e+10
node_memory_MemAvailable_bytes 9.834479616e+09
node_filesystem_size_bytes{device="/dev/mapper/root"} 1.07294887936e+11

출력량이 많으므로 처음 몇 줄만 확인하려면 다음 명령어를 사용합니다.

curl -s http://127.0.0.1:9100/metrics | head


0.55


9. Prometheus 확인

브라우저에서 다음 주소로 접속합니다.

http://서버-IP:9090

Prometheus 메뉴에서 다음 경로로 이동합니다.

Status → Targets

다음 두 대상이 UP 상태여야 합니다.

Job Target 예상 상태
prometheus localhost:9090 UP
node-exporter host.containers.internal:9100 UP

Prometheus 쿼리 화면에서 다음 쿼리를 실행할 수도 있습니다.

up

결과가 1이면 해당 대상에서 메트릭을 정상적으로 수집하고 있다는 의미입니다.

up{job="prometheus"} 1
up{job="node-exporter"} 1

결과가 0이면 대상이 등록되어 있지만 현재 수집에 실패한 상태입니다.


0.53


10. Grafana 접속

브라우저에서 다음 주소로 접속합니다.

http://서버-IP:3000

초기 관리자 계정은 기본 설정 기준으로 다음과 같습니다.

아이디: admin
비밀번호: admin

처음 로그인한 뒤에는 관리자 비밀번호를 반드시 변경합니다.

운영 환경에서는 Compose 파일에 초기 관리자 계정을 환경 변수로 설정할 수도 있습니다.

grafana:
  image: grafana/grafana:latest
  container_name: grafana
  restart: always
  environment:
    GF_SECURITY_ADMIN_USER: admin
    GF_SECURITY_ADMIN_PASSWORD: 변경할-강력한-비밀번호
  ports:
    - "3000:3000"
  volumes:
    - grafana-data:/var/lib/grafana:Z

비밀번호를 Git 저장소에 그대로 저장하는 방식은 권장하지 않습니다. 실제 운영 환경에서는 환경 파일, Secret 또는 별도의 비밀정보 관리 방법을 사용하는 것이 좋습니다.



11. Grafana에 Prometheus 연결

Grafana 로그인 후 다음 메뉴로 이동합니다.

Connections → Data sources → Add new data source

Prometheus를 선택하고 서버 URL에 다음 값을 입력합니다.

http://prometheus:9090

Grafana와 Prometheus는 같은 Compose 프로젝트의 기본 네트워크에 연결되므로 서비스 이름인 prometheus로 접근할 수 있습니다.

다음 주소를 입력하면 안 됩니다.

http://localhost:9090

Grafana 컨테이너에서 localhost는 Grafana 컨테이너 자신을 의미하기 때문입니다.

마지막으로 Save & test를 실행하여 연결 성공 여부를 확인합니다.


12. Grafana 대시보드 만들기

Grafana에서는 직접 패널을 만들거나 기존 대시보드 JSON을 가져올 수 있습니다.

직접 대시보드를 만들려면 다음 메뉴로 이동합니다.

Dashboards → New → New dashboard

패널을 추가한 후 데이터 소스로 Prometheus를 선택하고 PromQL을 입력합니다.

12.1 서버 정상 여부

up{job="node-exporter"}

  • 1: 정상
  • 0: 수집 실패 또는 서버 응답 없음

12.2 CPU 사용률

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

최근 5분간 CPU 유휴 시간을 기준으로 전체 CPU 사용률을 계산합니다.

12.3 메모리 사용률

(
  1 -
  (
    node_memory_MemAvailable_bytes
    /
    node_memory_MemTotal_bytes
  )
) * 100

전체 메모리 중 현재 사용 중인 메모리 비율을 계산합니다.

12.4 파일 시스템 사용률

100 - (
  node_filesystem_avail_bytes{
    fstype!~"tmpfs|overlay|squashfs"
  }
  /
  node_filesystem_size_bytes{
    fstype!~"tmpfs|overlay|squashfs"
  }
  * 100
)

임시 파일 시스템과 컨테이너 Overlay 파일 시스템을 제외한 디스크 사용률을 확인합니다.

마운트 위치별로 구분하려면 Grafana 범례에 다음 값을 사용할 수 있습니다.

{{instance}} - {{mountpoint}}

12.5 네트워크 수신량

rate(node_network_receive_bytes_total{device!="lo"}[5m])

Loopback 인터페이스를 제외한 초당 네트워크 수신 바이트를 확인합니다.

12.6 네트워크 송신량

rate(node_network_transmit_bytes_total{device!="lo"}[5m])

초당 네트워크 송신 바이트를 확인합니다.

12.7 서버 부하

node_load1

1분 Load Average를 확인합니다.

다음 메트릭도 함께 사용할 수 있습니다.

node_load5
node_load15


0.60