Prometheus Grafana Docker Compose 2GB RAM 서버 OOM 방지 메모리 설정값 정리

서버가 갑자기 멈췄어요. 로그를 보니 OOM killer가 Prometheus 프로세스를 죽인 거더라고요. 2GB RAM 서버에 Prometheus + Grafana + Docker Compose 올렸다가 메모리가 터지는 건, 2026년에도 여전히 흔한 패턴이에요. 문제는 공식 문서가 이 부분을 너무 얕게 다룬다는 거예요.
Prometheus의 기본 설정이 “서버 리소스는 충분하다"는 가정 위에 만들어졌기 때문이에요. 하지만 현실에서는 2GB RAM 서버 위에 애플리케이션 + 모니터링 스택을 같이 올리는 경우가 훨씬 많죠.
이 글에서는 실제 설정값과 그 근거를 데이터 기반으로 분석해드릴게요.
- Prometheus 메모리 사용 패턴과 OOM 발생 원인
- Docker Compose 레벨에서 컨테이너 메모리 제한 설정
- Grafana + Prometheus 동시 운영 시 실질적 메모리 배분
- 2GB RAM 환경에서 검증된 설정값 비교
핵심 요약
- Prometheus는 기본 설정 시
--storage.tsdb.retention.time=15d,--query.max-samples=50000000값을 사용하며, 2GB RAM 환경에서 단독으로도 800MB~1.2GB를 점유할 수 있어요.- Docker Compose의
mem_limit설정 없이 컨테이너를 올리면 호스트 메모리를 무제한으로 쓰는 구조라서, 2GB RAM 서버에서 OOM은 설정 실수가 아니라 기본 설정의 부재 문제예요.- Grafana는 최소 200
300MB를 소비하고,200MB가 더 필요해요.GF_RENDERING_SERVER_URL같은 플러그인 로드 시 추가로 100- Prometheus TSDB의
--storage.tsdb.min-block-duration조정과 scrape interval 변경만으로 메모리를 약 30~40% 줄일 수 있어요.
2GB RAM 환경에서 모니터링 스택이 왜 터지는가
Prometheus는 시계열 데이터를 메모리에 올려두는 방식으로 동작해요. 구체적으로는, scrape한 메트릭을 WAL(Write-Ahead Log)에 쓰기 전에 인메모리 헤드 블록에 먼저 적재해요.
Docker Recipes의 Prometheus + Grafana Docker Compose 레퍼런스 문서에 따르면, 기본 컴포즈 구성에는 메모리 제한(memory limit)이 포함되어 있지 않아요. 컨테이너가 호스트 메모리를 자유롭게 쓸 수 있는 구조죠.
여기서 문제가 생겨요.
2GB RAM 서버의 실제 가용 메모리는 보통 1.41.6GB 수준이에요. OS + Docker 데몬 자체가 400600MB를 이미 가져가거든요. 여기에 Prometheus 기본 설정으로 올리면 초기에는 괜찮아 보여요. 그런데 시간이 지날수록, 정확히는 메트릭 수집 대상이 늘거나 보존 기간이 쌓이면서 메모리가 선형에 가깝게 증가해요.
Last9의 Prometheus Docker Compose 가이드에 따르면, 모니터 대상 서비스가 5개 이상이고 scrape interval이 15초일 때, Prometheus 단독으로 600MB~1GB의 RSS 메모리를 기록한다고 나와요. 여기에 Grafana까지 올리면 총 1.5GB를 가볍게 넘기는 거예요.
결론은 간단해요. 기본 설정 그대로 2GB 서버에 올리면 OOM은 시간문제예요.
Prometheus TSDB 설정값: 어디서 메모리를 줄일 수 있나
보존 기간(Retention)과 메모리의 관계
가장 먼저 봐야 할 건 --storage.tsdb.retention.time이에요. 기본값은 15d(15일)인데, 이게 단순히 디스크 용량 문제가 아니에요.
TSDB는 최근 데이터를 메모리 헤드 블록에 유지하고, 2시간마다 디스크로 플러시해요. 보존 기간 자체는 RAM 사용량에 직접 영향을 주진 않지만, 쿼리 실행 시 로드하는 데이터 범위가 늘어나면서 간접적으로 메모리 압박을 줘요. Grafana 대시보드에서 7d, 30d 범위 쿼리를 자주 날린다면 더욱 두드러지죠.
2GB 환경에서는 보존 기간을 7d로 줄이는 게 현실적이에요.
command:
- '--storage.tsdb.retention.time=7d'
Scrape Interval과 샘플 수
기본 scrape_interval: 15s를 30s로 늘리면 단위 시간당 수집 샘플 수가 절반으로 줄어요. 인메모리 헤드 블록 크기도 그만큼 줄어들죠. 모니터링 정밀도를 약간 포기하는 대신 메모리를 아끼는 트레이드오프예요.
global:
scrape_interval: 30s
evaluation_interval: 30s
--query.max-samples 제한
기본값 50,000,000은 엄청난 메모리를 허용해요. 단일 쿼리가 RAM을 수백 MB 써버릴 수 있거든요. 2GB 환경에서는 10000000(1,000만) 수준으로 낮춰야 해요.
Docker Compose 레벨 메모리 제한 설정 비교
이게 핵심이에요. 아무리 Prometheus 설정을 잘해도 Docker Compose에서 mem_limit이 없으면 의미가 없어요.
| 설정 항목 | 기본값 | 2GB 서버 권장값 | 비고 |
|---|---|---|---|
Prometheus mem_limit | 없음 (무제한) | 512m | OOM killer 발동 전에 컨테이너 자체 조절 |
Prometheus memswap_limit | 없음 | 512m | swap 사용 방지 (성능 저하 예방) |
Grafana mem_limit | 없음 | 256m | 플러그인 최소화 시 충분 |
Grafana memswap_limit | 없음 | 256m | - |
| OS/Docker 예약 | 자동 | ~500m 예상 | 실제 가용 메모리 고려 시 |
| 총 합계 | — | ~1,268m | 2GB에서 안전 마진 유지 |
memswap_limit을 mem_limit과 동일하게 설정하면 swap을 쓰지 않겠다는 의미예요. swap은 OOM을 잠깐 막아주지만, 디스크 I/O가 폭발하면서 서버 전체가 응답 불능 상태가 되는 더 나쁜 상황을 만들기도 해요. 2GB 서버에서는 swap 의존보다 설정 조절이 낫죠.
Docker Compose 실제 설정 예시
services:
prometheus:
image: prom/prometheus:v2.51.0
mem_limit: 512m
memswap_limit: 512m
command:
- '--storage.tsdb.retention.time=7d'
- '--query.max-samples=10000000'
- '--storage.tsdb.min-block-duration=2h'
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:10.4.0
mem_limit: 256m
memswap_limit: 256m
environment:
- GF_ANALYTICS_REPORTING_ENABLED=false
- GF_PLUGINS_ENABLE_ALPHA=false
실제 운영 환경에서 어떻게 접근할 것인가
시나리오 1 — 단일 앱 + 모니터링 스택
앱 컨테이너 하나에 Prometheus + Grafana를 같이 올리는 구성이에요. 이 경우 앱에도 메모리 제한이 필요해요. 앱 256m, Prometheus 512m, Grafana 200m으로 배분하면 OS 예약 포함해서 약 1.9GB 수준이에요. 타이트하지만 가능은 해요.
단, Grafana 대시보드 패널을 10개 이상 띄우거나 Loki 같은 로그 백엔드를 붙이는 순간 이 배분은 깨져요.
시나리오 2 — 모니터링 전용 서버
2GB 서버를 모니터링 스택 전용으로 쓸 때예요. Prometheus 700m, Grafana 400m까지 올릴 수 있어요. 여기서는 --storage.tsdb.retention.time=15d도 가능하고, scrape interval도 15s로 유지할 수 있어요.
무엇을 모니터링해야 하는가
설정 후에는 반드시 컨테이너 메모리 사용량 자체를 추적해야 해요.
docker stats --no-stream
Prometheus가 제공하는 process_resident_memory_bytes 메트릭을 Grafana에서 직접 모니터링하면 더 정확해요. 메모리가 mem_limit의 80%를 넘어가기 시작하면 scrape 대상을 줄이거나 retention을 다시 조정해야 한다는 신호예요.
정리: 2GB에서 OOM 방지의 핵심은 “기본값 불신”
- Prometheus + Grafana + Docker Compose를 2GB RAM 서버에 올릴 때 OOM은 설정 실수가 아니라 기본값을 그대로 쓴 결과예요
mem_limit: 512m(Prometheus) +mem_limit: 256m(Grafana)는 2GB 환경 최소 설정이에요--storage.tsdb.retention.time=7d와scrape_interval: 30s변경으로 메모리를 30~40% 줄일 수 있어요--query.max-samples=10000000으로 단일 쿼리의 메모리 폭발을 막아요docker stats와process_resident_memory_bytes메트릭으로 지속 추적이 필수예요
6~12개월 안에 Prometheus 3.x의 네이티브 히스토그램이 더 보편화되면 동일 메트릭 수를 더 낮은 메모리로 처리하는 게 가능해질 거예요. 하지만 지금 당장 2GB 서버에서 OOM을 막아야 한다면, 설정 파일 다섯 줄 바꾸는 게 가장 빠른 길이에요.
지금 운영 중인 서버의 docker stats 출력을 한번 확인해보세요. Prometheus가 얼마나 먹고 있는지 보면, 이 설정값들이 왜 필요한지 바로 보일 거예요.
참고자료
- Prometheus + Grafana Docker Compose - Ready to Deploy | Docker Recipes
- Prometheus with Docker Compose: The Complete Setup Guide | Last9
Photo by Ales Nesetril on Unsplash


