테마 전환

Ollama 프로덕션 모니터링: 로그 설정과 Prometheus 알림 실전

Easton editorial illustration: agent rollout and rollback rail

새벽 3시 17분. Slack에 빨간 알림이 떴습니다. Ollama API timeout - service unavailable. 고객 지원 시스템을 출시한 지 2주째였고 하루에 수백 번 호출되고 있었습니다. 배포할 때 기본 로그만 설정했을 뿐 모니터링이나 알림은 전혀 없었습니다. GPU 메모리가 가득 찬 걸까요? 프로세스가 죽은 걸까요? 네트워크 문제일까요? 아무것도 알 수 없었습니다. 결국 아침 6시가 되어서야 복구했습니다.

70%
프로덕션에 안착하지 못하는 AI 프로젝트
Source: Hyperion Consulting 2026 보고서

모니터링 부재는 주요 원인 중 하나입니다.

이 글에서는 로그 설정부터 Prometheus + Grafana 모니터링, AlertManager 알림까지 완전한 구성을 소개합니다. 모두 그대로 복사해 사용할 수 있는 설정 파일입니다. 이 구성을 따르면 약 30분 만에 프로덕션 수준의 모니터링 체계를 구축할 수 있습니다.

프로덕션 모니터링의 핵심 과제

Ollama는 일반적인 웹 서비스와 조금 다릅니다. 자원을 아주 많이 먹습니다. 모델 하나를 로드할 때마다 메모리만 416GB를 차지합니다(Markaicode의 실제 테스트 데이터). 게다가 모델 콜드 스타트, 즉 디스크에서 메모리로 로드하는 데 1030초가 걸립니다. 서비스가 중단된 뒤 재시작되면 사용자는 응답을 받기까지 30초가량 기다려야 한다는 뜻입니다.

제가 겪은 문제는 주로 다음과 같았습니다.

메모리 누수와 GPU 고갈. 오랫동안 실행하면 Ollama가 때때로 VRAM 해제를 ‘잊어버립니다’. VRAM 24GB인 서버가 이틀 동안 실행된 뒤 가용 메모리가 2GB밖에 남지 않아 새 요청이 모두 거부된 적도 있습니다. 사용자가 항의할 때까지 무슨 일이 벌어졌는지 전혀 알지 못했다는 점이 문제였습니다.

요청 큐 적체. 추론 자체가 느려 요청 하나에 5~20초가 걸릴 수 있습니다. 수십 개의 요청이 동시에 들어오면 큐가 계속 쌓이다가 결국 타임아웃이 발생합니다. 하지만 큐가 실제로 쌓이고 있는지는 어떻게 알 수 있을까요? 추측할 수밖에 없습니다.

모델 로딩 지연. 여러 모델을 전환할 때 로딩 시간은 블랙박스입니다. 사용자는 응답이 왜 느린지 모르고, 운영자도 원인을 알 수 없습니다.

따라서 모니터링 목표는 명확합니다. 서비스 가용성(프로세스가 실행 중인가?), 성능 지표(응답 속도는 어떤가?), 자원 사용률(GPU 메모리가 얼마나 남았는가?), 오류율(요청이 얼마나 실패했는가?)입니다. 이 네 가지 영역을 파악해야 비로소 안심할 수 있습니다.

모니터링 구성을 선택하면서 여러 조합을 써봤습니다. 소규모 팀에는 Prometheus + Grafana만으로 충분합니다. LLM의 Prompt와 응답을 추적하려면 Langfuse가 유용합니다. 엔터프라이즈 환경이라면 OpenTelemetry를 기반으로 로그, 메트릭, 트레이스를 통합한 SigNoz를 고려할 수 있습니다. 여기서는 가장 범용적인 기반인 Prometheus 구성을 중점적으로 다루겠습니다.

로그 설정과 systemd 서비스 최적화

Ollama를 실행하는 것은 쉽지만 안정적으로 계속 운영하려면 먼저 로그부터 제대로 설정해야 합니다. 저도 문제가 생겨 로그를 확인했는데 아무것도 기록되지 않았거나, 수십 GB에 달하는 로그 파일이 디스크를 가득 채운 일을 겪었습니다.

systemd 서비스 설정

공식 스크립트로 Ollama를 직접 설치했다면 systemd 서비스도 이미 생성되어 있습니다. 다만 기본 설정은 단순하므로 프로덕션 환경에서는 몇 가지를 보완해야 합니다.

# /etc/systemd/system/ollama.service

[Unit]
Description=Ollama Service
After=network.target

[Service]
Type=simple
User=ollama
Group=ollama

# 작업 디렉터리
WorkingDirectory=/usr/share/ollama

# 환경 변수
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_MODELS=/data/ollama/models"
Environment="OLLAMA_DEBUG=1"
Environment="OLLAMA_LOG_FORMAT=json"

# 자원 제한(하드웨어에 맞게 조정)
LimitNOFILE=65535
LimitNPROC=4096
MemoryMax=32G

# 자동 재시작 정책
Restart=always
RestartSec=10

# 시작 명령
ExecStart=/usr/local/bin/ollama serve

# 표준 출력과 표준 오류
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

몇 가지 핵심 설정에 관한 제 경험을 설명하겠습니다.

Restart=alwaysRestartSec=10: 프로세스가 비정상 종료되면 자동으로 재시작하고, 시스템이 숨을 돌릴 수 있도록 10초 기다립니다. 메모리 고갈로 프로세스가 계속 충돌한 적이 있는데, 이 간격이 없으면 끊임없이 재시작하면서 로그가 폭증합니다.

MemoryMax=32G: Ollama가 사용할 수 있는 최대 메모리를 제한합니다. 같은 서버에 다른 서비스도 있다면 특히 중요합니다. 제한하지 않았다가 Ollama가 64GB 메모리를 모두 사용해 SSH 접속조차 할 수 없었던 적도 있습니다.

OLLAMA_DEBUG=1OLLAMA_LOG_FORMAT=json: 프로덕션 환경에서도 debug 모드를 켜두는 것을 권장합니다. 문제가 생겼을 때 원인을 찾기 쉽습니다. JSON 형식의 로그는 이후 도구로 분석하기도 편합니다.

설정을 바꾼 뒤에는 반드시 다시 로드하세요.

sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo systemctl enable ollama  # 부팅 시 자동 시작

Docker 배포의 로그 설정

Docker로 실행할 때는 로그 관리에서 실수하기 더 쉽습니다. Docker는 기본적으로 /var/lib/docker/containers/ 아래에 로그를 쓰며 제한을 두지 않으면 계속 커집니다.

제가 사용하는 docker-compose 설정은 다음과 같습니다.

# docker-compose.yml
version: '3.8'

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: always
    ports:
      - "11434:11434"
    volumes:
      - ./ollama_data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0:11434
      - OLLAMA_DEBUG=1
    deploy:
      resources:
        limits:
          memory: 32G
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"

max-size: "100m"은 로그 파일 하나의 최대 크기를 100MB로 제한하고, max-file: "5"는 파일을 5개 보관한다는 뜻입니다. 따라서 로그는 최대 500MB만 사용해 디스크를 가득 채우지 않습니다.

로그 수준 설명

Ollama에서 지원하는 환경 변수는 다음과 같습니다.

변수설명프로덕션 권장 설정
OLLAMA_DEBUG1로 설정해 상세 로그 활성화활성화 권장
OLLAMA_LOG_LEVEL로그 수준(INFO/DEBUG/WARN)INFO 또는 DEBUG
OLLAMA_LOG_FORMAT로그 형식(text/json)JSON

저는 보통 DEBUG를 계속 켜둡니다. 차지하는 디스크 공간은 크지 않지만 문제를 조사할 때 시간을 많이 절약할 수 있습니다.

journalctl 로그 확인 실전

설정을 마친 뒤에는 journalctl로 로그를 확인합니다.

# 실시간 로그 확인
sudo journalctl -u ollama -f

# 최근 100줄 확인
sudo journalctl -u ollama -n 100

# 오늘 로그 확인
sudo journalctl -u ollama --since today

# 특정 키워드 검색
sudo journalctl -u ollama | grep -i "error"

# 로그를 파일로 내보내기
sudo journalctl -u ollama --since "2026-04-12 00:00:00" > ollama-debug.log

한 가지 팁이 있습니다. JSON 형식 로그를 활성화했다면 jq로 분석할 수 있습니다.

sudo journalctl -u ollama -o json | jq 'select(.level=="error")'

이렇게 하면 수많은 INFO 로그를 뒤질 필요 없이 오류 수준의 로그만 볼 수 있습니다.

Prometheus + Grafana 모니터링 구성

로그가 사후 분석 도구라면 모니터링은 문제를 미리 알려주는 눈입니다. Prometheus + Grafana 조합을 2년 넘게 사용해 왔습니다. 설정이 조금 번거롭지만 안정적이고 신뢰할 수 있으며 커뮤니티 자료도 많습니다.

ollama-exporter 배포

Ollama 자체는 Prometheus 메트릭을 직접 노출하지 않으므로 exporter로 수집해야 합니다. 제가 사용하는 것은 frcooper/ollama-exporter입니다. Star는 많지 않지만(36개) 필요한 기능은 충분합니다.

배포 방법은 바이너리를 직접 실행하거나 Docker를 사용하는 두 가지입니다. Docker를 권장합니다.

# docker-compose.yml에 exporter 서비스 추가
services:
  ollama-exporter:
    image: frazco/ollama-exporter:latest
    container_name: ollama-exporter
    restart: always
    ports:
      - "9101:9101"
    environment:
      - OLLAMA_HOST=ollama:11434  # ollama 컨테이너 지정
    depends_on:
      - ollama

다음은 Prometheus 설정입니다.

# prometheus.yml
global:
  scrape_interval: 30s  # 샘플링 간격, Markaicode는 30초 권장
  evaluation_interval: 30s

scrape_configs:
  - job_name: 'ollama-exporter'
    static_configs:
      - targets: ['ollama-exporter:9101']
        labels:
          instance: 'ollama-prod'

  # GPU 모니터링(NVIDIA를 사용하는 경우)
  - job_name: 'nvidia-gpu'
    static_configs:
      - targets: ['localhost:9835']

Prometheus도 docker-compose에 추가합니다.

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'

volumes:
  prometheus_data:

핵심 모니터링 메트릭

ollama-exporter가 수집하는 메트릭 중 중요한 항목은 다음과 같습니다.

메트릭 이름설명확인할 점
ollama_requests_total전체 요청 수오류율 계산
ollama_requests_failed실패한 요청 수직접 모니터링
ollama_model_load_duration_seconds모델 로딩 시간콜드 스타트 성능
ollama_request_duration_seconds요청 응답 시간P95/P99 지연
ollama_tokens_per_second추론 속도throughput

시스템 계층 메트릭도 있습니다(node-exporter 필요).

  • CPU 사용률: node_cpu_seconds_total
  • 메모리 사용률: node_memory_MemAvailable_bytes
  • 네트워크 트래픽: node_network_receive_bytes_total

GPU 모니터링 설정

GPU는 LLM 서비스의 심장이므로 반드시 제대로 모니터링해야 합니다. 저는 nvidia_gpu_prometheus_exporter를 사용합니다.

# NVIDIA GPU exporter 설치
docker run -d \
  --name nvidia-exporter \
  --restart always \
  -p 9835:9835 \
  --gpus all \
  nvidia/gpu-prometheus-exporter:latest

다음과 같은 핵심 메트릭이 출력됩니다.

  • nvidia_gpu_utilization: GPU 사용률
  • nvidia_gpu_memory_used_bytes: VRAM 사용량
  • nvidia_gpu_memory_free_bytes: 남은 VRAM
  • nvidia_gpu_temperature: GPU 온도

멀티 GPU 환경에서는 메트릭에 gpu_id 레이블이 붙으므로 Grafana에서 GPU별로 표시할 수 있습니다.

Grafana Dashboard 설정

Grafana Dashboard에 바로 가져올 수 있는 JSON을 제공하겠습니다. 파일로 저장한 뒤 Grafana에서 Import Dashboard를 클릭하면 사용할 수 있습니다.

{
  "dashboard": {
    "title": "Ollama Production Monitor",
    "panels": [
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(ollama_requests_total[5m])",
            "legendFormat": "Requests/sec"
          }
        ],
        "gridPos": {"x": 0, "y": 0, "w": 12, "h": 6}
      },
      {
        "title": "Error Rate",
        "type": "gauge",
        "targets": [
          {
            "expr": "rate(ollama_requests_failed[5m]) / rate(ollama_requests_total[5m]) * 100",
            "legendFormat": "Error %"
          }
        ],
        "gridPos": {"x": 12, "y": 0, "w": 6, "h": 6}
      },
      {
        "title": "GPU Memory Usage",
        "type": "graph",
        "targets": [
          {
            "expr": "nvidia_gpu_memory_used_bytes / nvidia_gpu_memory_total_bytes * 100",
            "legendFormat": "GPU {{gpu_id}}"
          }
        ],
        "gridPos": {"x": 0, "y": 6, "w": 12, "h": 6}
      },
      {
        "title": "Response Latency P95",
        "type": "stat",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(ollama_request_duration_seconds_bucket[5m]))",
            "legendFormat": "P95 Latency"
          }
        ],
        "gridPos": {"x": 12, "y": 6, "w": 6, "h": 6}
      }
    ]
  },
  "overwrite": true
}

실제로는 대략 다음과 같이 표시됩니다.

  • 왼쪽 위: 요청 속도 그래프로 트래픽이 몰리는 시간대를 확인
  • 오른쪽 위: 오류율 게이지로 5%를 넘으면 빨간색으로 표시
  • 왼쪽 아래: 멀티 GPU 메모리 사용량 그래프
  • 오른쪽 아래: P95 지연 값

서로 다른 모델의 추론 속도를 나란히 비교할 수 있도록 Tokens/s 패널도 추가합니다.

Grafana 데이터 소스 설정

Grafana 컨테이너를 시작한 뒤 Prometheus 데이터 소스를 수동으로 설정해야 합니다.

  1. Grafana에 로그인합니다(기본 계정 admin/admin).
  2. Configuration -> Data Sources -> Add data source로 이동합니다.
  3. Prometheus를 선택하고 URL에 http://prometheus:9090을 입력합니다.
  4. Save & Test를 클릭합니다.

docker-compose로 함께 배포했다면 컨테이너 이름만으로 네트워크에서 바로 연결할 수 있습니다.

알림 규칙과 AlertManager 설정

모니터링으로 문제를 볼 수 있지만, 알림이 있어야 ‘지금 바로 대응해야 한다’는 사실을 알 수 있습니다. 예전에 모든 알림을 critical로 설정한 적이 있습니다. 휴대폰이 하루에도 수십 번 울리자 결국 무감각해졌고, 정작 심각한 문제가 생겨도 반응하지 않게 됐습니다.

알림 등급 전략

몇 번의 사고를 겪으며 알림을 다음 세 단계로 정리했습니다.

등급트리거 조건대응 요구 사항
Critical서비스 중단, GPU 메모리 95% 초과, 오류율 20% 초과즉시 대응(Slack + 모바일 푸시)
Warning응답 시간 60초 초과, GPU 메모리 80% 초과, 오류율 5% 초과1시간 안에 확인(Slack only)
Info모델 전환, 새 버전 배포기록만 수행(이메일 요약)

핵심 원칙은 Critical 알림을 최소화해 알림을 보는 즉시 긴장할 수 있게 하는 것입니다.

Prometheus 알림 규칙

prometheus.yml에 알림 규칙을 추가합니다.

rule_files:
  - 'ollama_alerts.yml'

그런 다음 별도의 ollama_alerts.yml을 작성합니다.

# ollama_alerts.yml
groups:
  - name: ollama_critical
    rules:
      # 서비스 중단 알림
      - alert: OllamaServiceDown
        expr: up{job="ollama-exporter"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Ollama 서비스 중단"
          description: "Ollama exporter에 연결할 수 없습니다. 서비스가 중지됐을 수 있습니다."

      # GPU 메모리 알림(>95%)
      - alert: GPUMemoryCritical
        expr: nvidia_gpu_memory_used_bytes / nvidia_gpu_memory_total_bytes > 0.95
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "GPU 메모리 고갈 임박"
          description: "GPU {{ gpu_id }} 메모리 사용률이 95%를 넘었습니다. 현재 값: {{ $value | humanizePercentage }}"

      # 높은 오류율 알림
      - alert: HighErrorRate
        expr: rate(ollama_requests_failed[5m]) / rate(ollama_requests_total[5m]) > 0.20
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "요청 오류율이 너무 높음"
          description: "지난 5분간 오류율이 20%를 넘었습니다. 로그를 확인하세요."

  - name: ollama_warning
    rules:
      # 응답 시간 알림
      - alert: SlowResponseTime
        expr: histogram_quantile(0.95, rate(ollama_request_duration_seconds_bucket[5m])) > 60
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "P95 응답 시간이 너무 느림"
          description: "요청의 95%에서 응답 시간이 60초를 넘었습니다."

      # GPU 메모리 사전 경고
      - alert: GPUMemoryWarning
        expr: nvidia_gpu_memory_used_bytes / nvidia_gpu_memory_total_bytes > 0.80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "GPU 메모리 사용률이 높음"
          description: "GPU {{ gpu_id }} 메모리 사용률이 80%를 넘었습니다."

      # 오류율 사전 경고
      - alert: ErrorRateWarning
        expr: rate(ollama_requests_failed[5m]) / rate(ollama_requests_total[5m]) > 0.05
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "요청 오류율 상승"
          description: "지난 5분간 오류율이 5%를 넘었습니다."

몇 가지 주의할 점이 있습니다.

  • for: Xm: X분 동안 상태가 지속되어야 알림을 발생시켜 순간적인 변동으로 인한 오탐을 방지합니다.
  • GPU 알림 임계값 95%: 실제로 테스트해 보면 95%를 넘은 뒤에는 거의 곧바로 문제가 발생합니다.
  • 오류율 알림에 rate() 사용: 절대적인 요청 수보다 추세가 중요하기 때문입니다.

AlertManager 설정

AlertManager는 알림 전송을 담당합니다. 설정 파일은 alertmanager.yml입니다.

global:
  resolve_timeout: 5m

# 라우팅 설정
route:
  group_by: ['severity', 'alertname']
  group_wait: 30s      # 같은 그룹의 알림을 모으기 위해 30초 대기
  group_interval: 5m   # 같은 그룹의 알림 간격
  repeat_interval: 3h  # 해결되지 않은 알림의 반복 전송 간격
  routes:
    - match:
        severity: critical
      receiver: 'critical-alerts'
      continue: false
    - match:
        severity: warning
      receiver: 'warning-alerts'
      continue: false
    - match:
        severity: info
      receiver: 'info-alerts'

# 수신자 설정
receivers:
  - name: 'critical-alerts'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
        channel: '#ollama-critical'
        send_resolved: true
        title: '{{ .Status | toUpper }}: {{ .CommonAnnotations.summary }}'
        text: '{{ .CommonAnnotations.description }}'

  - name: 'warning-alerts'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
        channel: '#ollama-monitor'
        send_resolved: true

  - name: 'info-alerts'
    email_configs:
      - to: '[email protected]'
        send_resolved: true

Slack Webhook 설정 단계

  1. Slack에서 App을 만듭니다(Incoming Webhooks를 사용해도 됩니다).
  2. Webhook URL을 api_url 필드에 추가합니다.
  3. channel을 분리하는 것을 권장합니다. critical에는 전용 채널을, warning에는 일반 채널을 사용합니다.

저는 모바일 푸시도 추가합니다. PagerDuty나 OpsGenie를 사용한다면 AlertManager에서 모두 연동할 수 있습니다. 비용을 들이고 싶지 않다면 설정이 그리 복잡하지 않은 Telegram Bot을 사용할 수도 있습니다.

음소거와 억제 규칙

유지보수 중에는 알림을 일시적으로 음소거해야 할 때가 있습니다. AlertManager UI에서 바로 설정할 수 있습니다.

# AlertManager UI 접속
http://your-server:9093

# Silences -> New Silence 클릭
# 지속 시간과 일치시킬 레이블 설정

API를 사용할 수도 있습니다.

curl -X POST http://localhost:9093/api/v1/silences \
  -d '{
    "matchers": [{"name": "alertname", "value": "OllamaServiceDown", "isRegex": false}],
    "startsAt": "2026-04-12T10:00:00Z",
    "endsAt": "2026-04-12T12:00:00Z",
    "createdBy": "admin",
    "comment": "Scheduled maintenance"
  }'

LLM 전용 모니터링 도구 심화

Prometheus + Grafana는 범용 구성이지만 LLM에는 Prompt 추적, Token 비용, 응답 품질 평가처럼 특별한 모니터링 요구 사항이 있습니다. 전통적인 모니터링 도구로는 이런 지표를 다루기 어렵습니다.

Langfuse: LLM 추적과 Prompt 관리

Langfuse는 LLM 애플리케이션을 위해 설계된 모니터링 플랫폼입니다. MIT 라이선스의 오픈 소스이며 셀프 호스팅을 지원합니다. 주요 기능은 다음과 같습니다.

  • 각 대화 추적: 입력 Prompt, 출력 내용, Token 수, 소요 시간 기록
  • Prompt 버전 관리: Prompt 변경 후 이전 버전과 새 버전의 효과 비교
  • 품질 평가: 사용자 피드백과 수동 레이블을 기록하고 모델 출력 품질 추적

연동 방법은 간단하며 Langfuse는 공식 Ollama 어댑터를 제공합니다.

# Python 연동 예제
from langfuse import Langfuse
import requests

langfuse = Langfuse(
    public_key="pk-xxx",
    secret_key="sk-xxx",
    host="https://cloud.langfuse.com"  # 또는 셀프 호스팅 주소
)

# 호출할 때마다 기록
trace = langfuse.trace(
    name="ollama-chat",
    input={"prompt": user_prompt},
    metadata={"model": "llama3.1"}
)

response = requests.post(
    "http://localhost:11434/api/generate",
    json={"model": "llama3.1", "prompt": user_prompt}
)

trace.update(
    output=response.json()["response"],
    metadata={"tokens": response.json().get("eval_count", 0)}
)

Langfuse 셀프 호스팅 버전은 Docker로 배포할 수 있습니다.

services:
  langfuse-server:
    image: langfuse/langfuse:latest
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/langfuse
      - NEXTAUTH_SECRET=your-secret

LangChain을 사용한다면 연동은 더 간단합니다. Langfuse가 공식 callback handler를 제공합니다.

SigNoz: OpenTelemetry 통합 모니터링

SigNoz는 OpenTelemetry 기반의 관측 가능성 플랫폼으로 로그, 메트릭, 트레이스를 하나로 통합합니다. Prometheus, Jaeger, ELK 세 가지 시스템을 각각 유지할 필요가 없다는 장점이 있습니다.

LLM 애플리케이션에서는 SigNoz의 트레이스 기능이 특히 유용합니다. API 진입점부터 모델 추론과 데이터베이스 쿼리까지 요청의 전체 흐름을 볼 수 있습니다.

SigNoz 배포에는 비교적 많은 자원이 필요하므로 메모리를 최소 4GB 확보하는 것이 좋습니다. 공식 Docker Compose로 한 번에 배포할 수 있습니다.

git clone https://github.com/SigNoz/signoz.git
cd signoz/deploy/docker
docker compose up -d

도구 선택 가이드

상황에 따라 다음 구성을 참고할 수 있습니다.

상황권장 구성이유
소규모 팀(5명 미만)Prometheus + Grafana간단하고 충분하며 커뮤니티 자료가 풍부함
Prompt 추적 필요Prometheus + LangfuseLLM에 집중하는 Langfuse와 상호 보완
엔터프라이즈 멀티 서비스SigNoz + OpenTelemetry통합 플랫폼으로 운영 비용이 더 낮음
완전한 클라우드 네이티브관리형 서비스 직접 사용운영 부담 절감

저는 현재 Prometheus + Grafana + Langfuse 조합을 사용합니다. Prometheus는 인프라 메트릭을, Langfuse는 LLM 애플리케이션 계층을 담당하도록 역할을 나눠 명확하게 관리합니다.

마치며

지금까지의 내용을 한 문장으로 요약하면 문제가 생긴 뒤에야 모니터링을 생각하지 마세요입니다.

새벽 3시에 겪은 일이 이 완전한 모니터링 구성으로 이어졌습니다. 지금은 Ollama 서비스를 1년 넘게 운영하고 있습니다. 그동안 GPU 메모리 알림이 몇 번 발생했지만 모두 Warning 단계에서 처리해 한밤중에 다시 호출되는 일은 없었습니다.

이 구성의 구축 비용은 사실 높지 않습니다. 다음 설정 파일을 모두 정리했으므로 바로 내려받아 사용할 수 있습니다.

  • systemd 서비스 설정
  • Docker Compose 전체 배포(Ollama + Exporter + Prometheus + Grafana)
  • Prometheus 알림 규칙
  • AlertManager 설정 템플릿
  • Grafana Dashboard JSON

관련 GitHub 저장소는 글 마지막에 두었습니다. 이 설정을 따르면 익숙한 사람은 20분, 초보자는 약 30분이면 실행할 수 있습니다.

다음 단계로 아래와 같이 진행해 보세요.

  1. 먼저 가장 기본적인 Prometheus + Grafana로 메트릭 수집을 시작합니다.
  2. 3~5일 동안 관찰하며 정상 상태의 데이터 범위를 파악합니다.
  3. 실제 상황에 맞게 알림 임계값을 조정합니다.
  4. Prompt 추적이 필요하다면 Langfuse를 추가합니다.

모니터링은 한 번 투자하면 효과가 계속됩니다. 저처럼 새벽 3시의 대가를 치르고서야 이 교훈을 얻는 일은 없기를 바랍니다.


설정 파일 저장소: github.com/yourname/ollama-monitoring-config(예시 링크이므로 실제 배포 시 교체하세요.)

시리즈 글:

FAQ

Ollama 프로덕션 환경에서 어떤 핵심 지표를 모니터링해야 하나요?
네 가지 영역을 봐야 합니다. 서비스 가용성(프로세스 실행 상태), 성능 지표(P95/P99 응답 지연), GPU 메모리 사용률(고갈 방지), 요청 오류율(이상 추세 추적)입니다.
Prometheus + Grafana와 Langfuse는 무엇이 다른가요?
Prometheus + Grafana는 CPU, GPU, 메모리, 요청량 같은 인프라 지표를 모니터링하고, Langfuse는 Prompt 추적, Token 비용, 응답 품질 평가 같은 LLM 애플리케이션 계층에 집중합니다. 서로 보완적이므로 함께 사용하는 것을 권장합니다.
알림 임계값은 어떻게 설정해야 적절한가요?
세 단계로 나누는 것을 권장합니다. Critical(GPU 메모리 95% 초과, 오류율 20% 초과, 서비스 중단)은 즉시 대응하고, Warning(GPU 메모리 80% 초과, 오류율 5% 초과)은 1시간 안에 확인합니다. 핵심은 Critical 알림 수를 줄여 알림을 보는 즉시 긴장할 수 있게 하는 것입니다.
Docker 배포에서 로그 파일이 끝없이 커지면 어떻게 하나요?
docker-compose.yml의 logging 설정에 max-size: "100m"와 max-file: "5"를 추가하세요. 로그 파일 하나를 100MB로 제한하고 최대 5개만 보관하므로 전체 용량이 500MB를 넘지 않습니다.
멀티 GPU 환경에서 각 GPU를 따로 모니터링하려면 어떻게 하나요?
nvidia_gpu_prometheus_exporter 메트릭에는 gpu_id 레이블이 포함됩니다. Grafana의 PromQL에서 {{gpu_id}}를 legendFormat으로 사용하면 GPU별로 표시할 수 있습니다.
새벽 3시에 알림을 받으면 어떻게 문제를 빠르게 찾을 수 있나요?
먼저 GPU 메모리 그래프를 확인해 메모리가 가득 찼는지 봅니다. 다음으로 오류율 추세가 갑자기 치솟았는지 서서히 나빠졌는지 확인하고, 마지막으로 journalctl 로그에서 구체적인 오류를 찾습니다. 이 순서라면 10분 안에 근본 원인을 찾는 데 도움이 됩니다.

4분 읽기 · 게시일: 2026년 4월 12일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog