Docker 컨테이너 모니터링: cAdvisor + Prometheus + Grafana

본 글은 Claude Sonnet 4.6으로 작성되었습니다.

MLOps 환경에서 수십 개의 컨테이너가 동시에 돌아갈 때, "지금 GPU 메모리는 얼마나 쓰고 있지?", "어떤 컨테이너가 CPU를 잡아먹고 있지?" 같은 질문이 자연스럽게 생긴다. 이 글에서는 cAdvisor, Prometheus, Grafana를 조합해 컨테이너 리소스를 실시간으로 모니터링하는 스택을 구성하는 방법을 다룬다.


세 도구의 역할과 관계

각 도구가 어떤 역할을 하는지 먼저 파악하는 것이 중요하다.

cAdvisor (Container Advisor)

Google이 만든 오픈소스 도구이다. Docker 데몬의 소켓(/var/run/docker.sock)에 직접 접근해 각 컨테이너의 CPU, 메모리, 네트워크, 디스크 I/O 등의 원시 메트릭(raw metrics) 을 수집한다. 수집된 메트릭은 /metrics 엔드포인트를 통해 Prometheus 포맷으로 노출된다.

Prometheus

시계열(time-series) 데이터베이스이자 모니터링 시스템이다. cAdvisor처럼 메트릭을 노출하는 엔드포인트를 주기적으로 스크래핑(scraping) 해서 데이터를 저장한다. 단순히 데이터를 모으는 것 외에도, PromQL이라는 쿼리 언어로 복잡한 집계와 필터링이 가능하다.

Grafana

데이터 시각화 플랫폼이다. Prometheus를 데이터 소스(data source)로 연결하면, PromQL 쿼리 결과를 그래프, 게이지, 히트맵 등 다양한 형태로 시각화할 수 있다. 사전에 만들어진 대시보드 템플릿을 임포트해서 바로 쓸 수도 있다.

세 도구의 데이터 흐름

Docker 컨테이너
    │
    │ (컨테이너 메트릭 노출)
    ▼
cAdvisor  ──(HTTP /metrics)──▶  Prometheus  ──(PromQL 쿼리)──▶  Grafana
                                    │
                                (시계열 저장)

정리하면, cAdvisor는 수집, Prometheus는 저장, Grafana는 시각화를 담당한다.


docker-compose.yml 작성

세 서비스를 한 번에 올리는 docker-compose.yml을 작성한다.

# docker-compose.yml

version: "3.8"

services:

  # ─────────────────────────────────────────────
  # cAdvisor: 컨테이너 메트릭 수집기
  # Google이 만든 도구로, Docker 소켓을 마운트해
  # 각 컨테이너의 CPU/메모리/네트워크 정보를 읽는다.
  # ─────────────────────────────────────────────
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.47.2
    container_name: cadvisor
    ports:
      - "8080:8080"   # 브라우저에서 http://localhost:8080 으로 cAdvisor UI 접근 가능
    volumes:
      # Docker 데몬 소켓: 컨테이너 목록과 상태 정보를 읽기 위해 필요
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # 호스트 루트 파일시스템: 디스크/네트워크 통계를 읽기 위해 필요
      - /:/rootfs:ro
      # 호스트 /sys: cgroup, 네트워크 인터페이스 정보 접근
      - /sys:/sys:ro
      # Docker 데이터 디렉토리: 컨테이너 스토리지 정보
      - /var/lib/docker/:/var/lib/docker:ro
    privileged: true   # cgroup 등 시스템 레벨 정보에 접근하기 위해 필요
    restart: unless-stopped

  # ─────────────────────────────────────────────
  # Prometheus: 시계열 메트릭 저장소
  # cAdvisor의 /metrics 엔드포인트를 주기적으로 스크래핑해
  # 메트릭을 저장하고 PromQL 쿼리를 제공한다.
  # ─────────────────────────────────────────────
  prometheus:
    image: prom/prometheus:v2.48.0
    container_name: prometheus
    ports:
      - "9090:9090"   # Prometheus Web UI: http://localhost:9090
    volumes:
      # prometheus.yml: 스크래핑 대상과 주기를 정의하는 설정 파일
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      # 메트릭 데이터 영구 저장을 위한 볼륨
      - prometheus_data:/prometheus
    command:
      # 설정 파일 경로 명시
      - "--config.file=/etc/prometheus/prometheus.yml"
      # 데이터 보존 기간 설정 (기본값은 15d)
      - "--storage.tsdb.retention.time=30d"
    restart: unless-stopped

  # ─────────────────────────────────────────────
  # Grafana: 메트릭 시각화 대시보드
  # Prometheus를 데이터 소스로 연결해 그래프/게이지 등으로 시각화한다.
  # ─────────────────────────────────────────────
  grafana:
    image: grafana/grafana:10.2.2
    container_name: grafana
    ports:
      - "3000:3000"   # Grafana Web UI: http://localhost:3000 (기본 계정: admin/admin)
    environment:
      # 초기 관리자 비밀번호 설정 (실제 운영 환경에서는 반드시 변경)
      - GF_SECURITY_ADMIN_PASSWORD=admin
      # 익명 접근 비활성화 (보안을 위해 기본값 유지 권장)
      - GF_AUTH_ANONYMOUS_ENABLED=false
    volumes:
      # Grafana 설정, 대시보드, 플러그인 데이터 영구 저장
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus   # Prometheus가 먼저 실행된 후 Grafana 시작
    restart: unless-stopped

# ─────────────────────────────────────────────
# Named Volume 선언
# Docker가 관리하는 영구 볼륨으로, 컨테이너를 내려도 데이터가 유지된다.
# ─────────────────────────────────────────────
volumes:
  prometheus_data:
  grafana_data:

prometheus.yml 작성

Prometheus가 어디서 메트릭을 가져올지 정의하는 설정 파일이다. docker-compose.yml과 같은 디렉터리에 위치시킨다.

# prometheus.yml

# ─────────────────────────────────────────────
# global: 전역 설정
# 개별 job에서 재정의하지 않으면 이 값이 기본으로 적용된다.
# ─────────────────────────────────────────────
global:
  # scrape_interval: 메트릭을 수집하는 주기
  # 15s는 Prometheus 권장 기본값이다.
  scrape_interval: 15s
  # evaluation_interval: alerting rule을 평가하는 주기
  evaluation_interval: 15s

# ─────────────────────────────────────────────
# scrape_configs: 스크래핑 대상 목록
# 각 항목을 'job'이라고 부른다.
# ─────────────────────────────────────────────
scrape_configs:

  # ── Prometheus 자기 자신을 모니터링 ──
  # Prometheus도 자체 메트릭을 /metrics로 노출한다.
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  # ── cAdvisor 스크래핑 ──
  # docker-compose 내부 네트워크에서는 서비스 이름을 호스트명으로 사용한다.
  # 즉, 'cadvisor:8080'은 cAdvisor 컨테이너의 8080 포트를 가리킨다.
  - job_name: "cadvisor"
    scrape_interval: 10s   # 컨테이너 메트릭은 변화가 빠르므로 더 짧은 주기로 수집
    static_configs:
      - targets: ["cadvisor:8080"]
    # metric_relabel_configs: 불필요한 메트릭을 드롭해 저장 용량을 줄일 수 있다.
    # 아래는 예시이며 필요에 따라 활성화한다.
    # metric_relabel_configs:
    #   - source_labels: [__name__]
    #     regex: "container_tasks_state|container_memory_failures_total"
    #     action: drop

실행 및 확인

설정 파일이 준비되면 아래 명령어로 전체 스택을 실행한다.

# 모든 서비스를 백그라운드에서 실행
docker compose up -d

# 실행 중인 컨테이너 상태 확인
docker compose ps

# 특정 서비스 로그 확인 (예: prometheus)
docker compose logs -f prometheus

실행 후 각 서비스에 접근한다.

서비스 주소 설명

cAdvisor http://localhost:8080 컨테이너별 리소스 사용 현황
Prometheus http://localhost:9090 PromQL 쿼리 및 타겟 상태 확인
Grafana http://localhost:3000 대시보드 (초기 계정: admin/admin)

Prometheus에서 http://localhost:9090/targets 를 열어 cAdvisor 타겟이 UP 상태인지 확인하는 것이 첫 번째 디버깅 포인트이다.


Grafana 대시보드 설정

Grafana에 처음 로그인하면 데이터 소스와 대시보드를 설정해야 한다.

1. Prometheus 데이터 소스 추가

Connections > Data Sources > Add data source > Prometheus 로 이동한 뒤, URL에 http://prometheus:9090 을 입력한다. (Docker 내부 네트워크를 사용하므로 서비스 이름으로 접근한다.)

2. 대시보드 임포트

처음부터 대시보드를 만들 필요 없이, Grafana 공식 대시보드 라이브러리에서 템플릿을 가져다 쓸 수 있다. Dashboards > Import 에서 아래 ID를 입력하면 바로 사용 가능한 대시보드가 설치된다.

  • 193: Docker 컨테이너 모니터링 (cAdvisor 기반)
  • 11600: Docker Container & Host Metrics

자주 쓰는 PromQL 예시

Prometheus에서 직접 쿼리하거나 Grafana 패널에서 사용하는 PromQL 예시이다.

# 컨테이너별 CPU 사용률 (%)
# rate()로 초당 CPU 사용량을 계산하고, 100을 곱해 퍼센트로 변환
sum(rate(container_cpu_usage_seconds_total{name!=""}[1m])) by (name) * 100

# 컨테이너별 메모리 사용량 (MB)
# container_memory_usage_bytes: 현재 메모리 사용량 (bytes)
container_memory_usage_bytes{name!=""} / 1024 / 1024

# 컨테이너별 네트워크 수신 트래픽 (bps)
sum(rate(container_network_receive_bytes_total{name!=""}[1m])) by (name)

마무리

세 도구의 역할을 다시 정리한다.

  • cAdvisor: 컨테이너 메트릭을 Docker 소켓에서 읽어 HTTP로 노출
  • Prometheus: cAdvisor의 메트릭을 주기적으로 스크래핑해 시계열 DB에 저장
  • Grafana: Prometheus 데이터를 시각화

이 스택은 MLOps 환경에서 학습 컨테이너의 리소스 사용 패턴을 파악하거나, 특정 컨테이너가 메모리 누수를 일으키는지 추적하는 데 실질적인 도움이 된다. 알림(alerting)이 필요하다면 Prometheus의 Alertmanager를 추가로 연동하는 것도 고려해볼 만하다.