Docker 로깅과 모니터링 — 로그 드라이버, Prometheus, cAdvisor

Docker 로깅 기본

Docker 컨테이너의 stdout/stderr 출력은 로그 드라이버를 통해 수집됩니다. 기본 로그 드라이버는 json-file로, 호스트 파일시스템에 JSON 형태로 저장합니다.

# 컨테이너 로그 확인
docker logs my-app
# 2026-03-11T14:00:00.000Z  info  Server started on port 3000
# 2026-03-11T14:00:01.234Z  info  Connected to database
# 2026-03-11T14:00:05.678Z  warn  High memory usage: 85%

# 최근 100줄만 확인
docker logs --tail 100 my-app

# 실시간 로그 스트리밍
docker logs -f my-app

# 타임스탬프 포함
docker logs -t my-app
# 2026-03-11T14:00:00.000000000Z  info  Server started on port 3000

# 시간 범위 필터
docker logs --since "2026-03-11T14:00:00" --until "2026-03-11T15:00:00" my-app

# 로그 파일 위치 확인
docker inspect --format='{{.LogPath}}' my-app
# /var/lib/docker/containers/abc123.../abc123...-json.log

기본 설정에서 로그 파일은 무한히 커질 수 있습니다. 프로덕션에서는 반드시 로그 로테이션을 설정해야 합니다.

로그 드라이버 설정

Docker는 다양한 로그 드라이버를 지원합니다.

드라이버저장 위치docker logs 지원주요 특징
json-file로컬 JSON 파일지원기본값, 로테이션 설정 가능
local최적화된 로컬 파일지원json-file보다 효율적
syslogsyslog 서버미지원중앙 로그 서버로 전송
journaldsystemd journal지원systemd 환경에 적합
fluentdFluentd 수집기미지원EFK 스택과 연동
awslogsCloudWatch미지원AWS 환경에 적합

json-file 로그 로테이션

// /etc/docker/daemon.json — 전역 로그 설정
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5",
    "compress": "true",
    "tag": "{{.ImageName}}/{{.Name}}"
  }
}
# 설정 적용
sudo systemctl restart docker

# 컨테이너별 개별 설정 (전역 설정 오버라이드)
docker run -d \
  --name api \
  --log-driver json-file \
  --log-opt max-size=100m \
  --log-opt max-file=10 \
  my-app:latest

# Docker Compose에서 로그 설정
# docker-compose.yml
# services:
#   api:
#     image: my-app:latest
#     logging:
#       driver: json-file
#       options:
#         max-size: "50m"
#         max-file: "5"

local 드라이버 (권장)

local 드라이버는 json-file보다 디스크 사용이 효율적이며, 기본적으로 로테이션이 설정되어 있습니다.

// /etc/docker/daemon.json
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5"
  }
}

구조화된 로그 출력

애플리케이션에서 JSON 형태로 로그를 출력하면 로그 분석과 검색이 쉬워집니다.

// Node.js 구조화된 로그 예제 (pino 라이브러리)
const pino = require('pino');

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  // JSON 형식으로 출력 (Docker 로그 드라이버와 호환)
  formatters: {
    level: (label) => ({ level: label }),
  },
  // 타임스탬프 포함
  timestamp: pino.stdTimeFunctions.isoTime,
});

// 사용 예
logger.info({ userId: 123, action: 'login' }, '사용자 로그인');
// {"level":"info","time":"2026-03-11T14:00:00.000Z","userId":123,"action":"login","msg":"사용자 로그인"}

logger.error({ err: error, requestId: 'abc' }, '요청 처리 실패');
// {"level":"error","time":"2026-03-11T14:00:01.000Z","err":{"message":"...","stack":"..."},"requestId":"abc","msg":"요청 처리 실패"}

cAdvisor — 컨테이너 리소스 모니터링

cAdvisor(Container Advisor)는 Google이 개발한 컨테이너 모니터링 도구입니다. 각 컨테이너의 CPU, 메모리, 네트워크, 디스크 사용량을 실시간으로 수집합니다.

# cAdvisor 실행
docker run -d \
  --name cadvisor \
  --privileged \
  -p 8080:8080 \
  -v /:/rootfs:ro \
  -v /var/run:/var/run:ro \
  -v /sys:/sys:ro \
  -v /var/lib/docker/:/var/lib/docker:ro \
  -v /dev/disk/:/dev/disk:ro \
  gcr.io/cadvisor/cadvisor:latest

# 웹 UI 접근: http://localhost:8080
# API로 메트릭 조회: http://localhost:8080/api/v1.3/docker/
# Prometheus 메트릭 엔드포인트: http://localhost:8080/metrics

cAdvisor는 자체 웹 UI도 제공하지만, Prometheus와 연동하여 장기간 데이터를 저장하고 Grafana로 시각화하는 것이 일반적입니다.

Prometheus + Grafana 모니터링 스택

Prometheus(메트릭 수집/저장) + Grafana(시각화) + cAdvisor(컨테이너 메트릭)를 Docker Compose로 구성합니다.

# monitoring/docker-compose.yml
# 컨테이너 모니터링 스택

services:
  # Prometheus — 메트릭 수집 및 저장
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      # 메트릭 보존 기간: 30일
      - '--storage.tsdb.retention.time=30d'
    networks:
      - monitoring

  # Grafana — 대시보드 시각화
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus
    networks:
      - monitoring

  # cAdvisor — 컨테이너 메트릭 수집
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    privileged: true
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    networks:
      - monitoring

  # Node Exporter — 호스트 시스템 메트릭
  node-exporter:
    image: prom/node-exporter:latest
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
    networks:
      - monitoring

networks:
  monitoring:
    driver: bridge

volumes:
  prometheus-data:
  grafana-data:

Prometheus 설정

# monitoring/prometheus.yml
# Prometheus 수집 대상 설정

global:
  # 15초마다 메트릭 수집
  scrape_interval: 15s
  # 평가 주기
  evaluation_interval: 15s

scrape_configs:
  # Prometheus 자체 메트릭
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # cAdvisor 컨테이너 메트릭
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

  # Node Exporter 호스트 메트릭
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  # 애플리케이션 메트릭 (앱에서 /metrics 엔드포인트 제공 시)
  - job_name: 'my-app'
    static_configs:
      - targets: ['api:3000']
    metrics_path: '/metrics'
# 모니터링 스택 실행
cd monitoring
docker compose up -d

# Prometheus 접속: http://localhost:9090
# Grafana 접속: http://localhost:3000 (admin / 설정한 비밀번호)

# Prometheus에서 컨테이너 CPU 사용량 쿼리 (PromQL)
# rate(container_cpu_usage_seconds_total{name=~".+"}[5m])

# 컨테이너 메모리 사용량 쿼리
# container_memory_usage_bytes{name=~".+"}

알림 설정

Prometheus Alertmanager로 임계값 초과 시 알림을 보냅니다.

# monitoring/alert-rules.yml
# Prometheus 알림 규칙

groups:
  - name: container-alerts
    rules:
      # 컨테이너 다운 알림
      - alert: ContainerDown
        # 5분 동안 컨테이너가 실행되지 않으면 알림
        expr: absent(container_last_seen{name=~"myapp_.+"})
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "컨테이너 다운: {{ $labels.name }}"

      # CPU 사용률 80% 초과
      - alert: HighCpuUsage
        expr: rate(container_cpu_usage_seconds_total{name=~".+"}[5m]) > 0.8
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "높은 CPU 사용률: {{ $labels.name }} ({{ $value }})"

      # 메모리 사용률 90% 초과
      - alert: HighMemoryUsage
        expr: container_memory_usage_bytes{name=~".+"} / container_spec_memory_limit_bytes{name=~".+"} > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "높은 메모리 사용률: {{ $labels.name }}"

      # 디스크 사용률 85% 초과
      - alert: HighDiskUsage
        expr: (node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes > 0.85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "디스크 사용률 85% 초과: {{ $labels.mountpoint }}"

docker stats — 간단한 실시간 모니터링

별도 도구 없이 Docker CLI만으로 컨테이너 리소스를 확인할 수 있습니다.

# 실시간 리소스 모니터링
docker stats
# CONTAINER ID  NAME   CPU %  MEM USAGE / LIMIT   MEM %  NET I/O        BLOCK I/O
# abc123        api    2.50%  256MiB / 512MiB      50%    1.2MB / 800kB  5MB / 2MB
# def456        db     1.20%  128MiB / 1GiB        12%    500kB / 1MB    50MB / 20MB
# ghi789        redis  0.10%  32MiB / 256MiB       12%    100kB / 50kB   0B / 0B

# 특정 컨테이너만 (비스트리밍, 현재 상태만)
docker stats --no-stream api db

# 커스텀 포맷
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
# NAME   CPU %   MEM USAGE / LIMIT   MEM %
# api    2.50%   256MiB / 512MiB     50.00%
# db     1.20%   128MiB / 1GiB       12.50%

정리

  • 로그 로테이션 필수: 프로덕션에서 로그 로테이션 없이 운영하면 디스크가 가득 차서 서비스가 중단됩니다. daemon.jsonmax-sizemax-file을 반드시 설정하세요. local 드라이버는 기본 로테이션이 적용되어 편리합니다.
  • 구조화된 로그: JSON 형태의 로그를 출력하면 EFK/ELK 스택이나 CloudWatch 같은 로그 분석 도구에서 필드별 검색과 필터링이 가능합니다. 평문 로그보다 운영 효율이 높습니다.
  • Grafana 대시보드: Docker 모니터링용 커뮤니티 대시보드(ID: 193, 1860 등)를 임포트하면 별도 설정 없이 바로 사용할 수 있습니다. Grafana 접속 후 Dashboards → Import에서 ID를 입력하세요.
  • 알림 채널: Alertmanager와 Slack, PagerDuty, 이메일 등을 연동하여 장애 알림을 받으세요. 알림 없는 모니터링은 대시보드를 계속 쳐다보고 있어야 하므로 의미가 반감됩니다.
  • 보존 기간과 스토리지: Prometheus 메트릭 보존 기간(--storage.tsdb.retention.time)을 서비스 규모에 맞게 설정하세요. 30일이면 대부분 충분하며, 장기 분석이 필요하면 Thanos나 Mimir로 원격 스토리지를 구성합니다.

이 글이 도움이 되었나요?