본 글은 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를 추가로 연동하는 것도 고려해볼 만하다.