리소스 설정이 왜 어려운가
Kubernetes에서 requests와 limits를 잘못 설정하면 두 가지 문제가 발생합니다. 너무 높으면 클러스터 리소스가 낭비되고 비용이 증가합니다. 너무 낮으면 OOMKilled, CPU 스로틀링으로 서비스 장애가 발생합니다. 대부분의 팀이 “넉넉하게” 설정하고 잊어버리지만, 실제 사용량과의 괴리가 40~70%에 달하는 경우가 흔합니다.
이 글에서는 requests vs limits의 정확한 의미, QoS 클래스별 OOM 순서, 메트릭 기반 Right-Sizing 방법, CPU 스로틀링 진단, 그리고 VPA·Goldilocks 자동 추천까지 심층적으로 다룹니다.
requests vs limits 정확한 이해
이 두 값은 완전히 다른 목적을 가집니다:
| 구분 | requests | limits |
|---|---|---|
| 역할 | 스케줄링 기준 — 노드 배치 결정 | 런타임 상한 — 초과 시 제한/종료 |
| CPU 초과 | 다른 Pod가 안 쓰면 더 사용 가능 | 스로틀링 (강제 대기) |
| 메모리 초과 | 다른 Pod가 안 쓰면 더 사용 가능 | OOMKilled (즉시 종료) |
| 미설정 시 | BestEffort QoS → 가장 먼저 퇴거 | 무제한 사용 가능 |
resources:
requests:
cpu: 250m # 0.25 코어 — "최소 이만큼은 보장해줘"
memory: 256Mi # 256MB — "최소 이만큼은 보장해줘"
limits:
cpu: "1" # 1 코어 — "이 이상은 절대 못 써"
memory: 512Mi # 512MB — "이 이상 쓰면 OOMKilled"
QoS 클래스와 OOM 우선순위
노드 메모리가 부족하면 kubelet이 Pod를 QoS 클래스 순서대로 종료합니다:
# 1. Guaranteed — 가장 마지막에 종료
# requests == limits (CPU, 메모리 모두)
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 500m # requests와 동일
memory: 512Mi # requests와 동일
# 2. Burstable — 중간 우선순위
# requests < limits (또는 일부만 설정)
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1" # requests보다 높음
memory: 512Mi
# 3. BestEffort — 가장 먼저 종료
# requests/limits 모두 미설정
resources: {}
# 퇴거 순서: BestEffort → Burstable(사용량 높은 순) → Guaranteed
메트릭 기반 Right-Sizing
현재 리소스 설정이 적절한지 실제 사용량 데이터로 판단합니다:
# 1. 현재 리소스 사용량 확인
kubectl top pods -n production --sort-by=cpu
kubectl top pods -n production --sort-by=memory
# 2. requests 대비 실제 사용 비율
kubectl top pods -n production -o json | jq '
.items[] | {
name: .metadata.name,
cpu_used: .containers[0].usage.cpu,
mem_used: .containers[0].usage.memory
}'
# 3. Prometheus로 장기 메트릭 분석 (7일)
# CPU: 평균 사용량
avg by (pod) (
rate(container_cpu_usage_seconds_total{
namespace="production",
container!="POD"
}[5m])
) / on(pod) group_left()
kube_pod_container_resource_requests{
resource="cpu"
}
# 메모리: P99 사용량 (피크 기준)
quantile_over_time(0.99,
container_memory_working_set_bytes{
namespace="production",
container!="POD"
}[7d]
) / on(pod) group_left()
kube_pod_container_resource_requests{
resource="memory"
}
CPU 스로틀링 진단
CPU limits를 너무 낮게 설정하면 스로틀링이 발생하여 응답 지연이 생깁니다. OOMKilled와 달리 Pod가 재시작되지 않아 발견하기 어렵습니다:
# CPU 스로틀링 확인
# throttled_periods: 스로틀링 발생 횟수
# throttled_time: 스로틀링으로 대기한 총 시간
# Prometheus 쿼리: 스로틀링 비율
rate(container_cpu_cfs_throttled_periods_total{
namespace="production"
}[5m])
/
rate(container_cpu_cfs_periods_total{
namespace="production"
}[5m])
# 30% 이상이면 CPU limits 증가 필요
# → 응답 지연의 숨은 원인인 경우가 많음
# 해결 방법들:
# 1) CPU limits 증가
# 2) CPU limits 제거 (requests만 설정)
# 3) Pod 수평 확장 (HPA)
논쟁: 많은 팀이 CPU limits를 아예 설정하지 않는 전략을 채택합니다. Google의 내부 권장사항이기도 합니다:
# CPU limits 미설정 전략 (권장하는 팀 多)
resources:
requests:
cpu: 250m # 스케줄링과 QoS용
memory: 256Mi
limits:
# cpu: 생략! # 스로틀링 방지 — 유휴 CPU 활용
memory: 512Mi # 메모리 limits는 반드시 설정 (OOM 방지)
Goldilocks로 자동 추천
Goldilocks는 VPA의 추천 값을 대시보드로 시각화해줍니다:
# Goldilocks 설치
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install goldilocks fairwinds-stable/goldilocks -n goldilocks --create-namespace
# 네임스페이스에 Goldilocks 활성화
kubectl label ns production goldilocks.fairwinds.com/enabled=true
# VPA 객체가 자동 생성되어 추천값 수집 시작
# 대시보드에서 각 Deployment별 추천 requests/limits 확인
kubectl -n goldilocks port-forward svc/goldilocks-dashboard 8080:80
# → http://localhost:8080
Goldilocks 대시보드는 각 컨테이너에 대해 Lower Bound, Target, Upper Bound, Uncapped Target 4가지 추천값을 보여줍니다:
| 추천 유형 | 설명 | 활용 |
|---|---|---|
| Lower Bound | 최소 권장값 | requests 하한선 |
| Target | 최적 추천값 | requests 설정 기준 |
| Upper Bound | 상위 안전 마진 | limits 설정 기준 |
| Uncapped Target | LimitRange 무시 추천 | 실제 필요량 참고 |
Right-Sizing 실전 공식
# 권장 공식:
# CPU requests = P99 사용량 (7일 기준)
# CPU limits = 미설정 또는 requests × 3~5배
# Memory requests = P99 사용량 × 1.2 (20% 마진)
# Memory limits = requests × 1.5~2배
# 예시: 7일간 CPU P99=200m, Memory P99=180Mi
resources:
requests:
cpu: 200m # P99 사용량
memory: 220Mi # 180Mi × 1.2
limits:
# cpu: 미설정 # 스로틀링 방지
memory: 440Mi # 220Mi × 2
# 주기적 리뷰 (월 1회)
# 1. Goldilocks 대시보드 확인
# 2. 스로틀링 메트릭 확인
# 3. OOMKilled 이벤트 확인
# 4. requests/limits 조정
비용 절감 효과 측정
# 현재 낭비량 계산 (Prometheus)
# CPU 낭비: requests - 실제 사용량
sum(
kube_pod_container_resource_requests{resource="cpu", namespace="production"}
-
rate(container_cpu_usage_seconds_total{namespace="production"}[5m])
)
# 메모리 낭비
sum(
kube_pod_container_resource_requests{resource="memory", namespace="production"}
-
container_memory_working_set_bytes{namespace="production"}
)
# 일반적으로 Right-Sizing 후:
# - 클러스터 노드 수 20~40% 감소
# - 월 클라우드 비용 25~35% 절감
# - OOMKilled/스로틀링 90% 이상 감소
마무리
Kubernetes 리소스 Right-Sizing은 비용 최적화와 서비스 안정성을 동시에 달성하는 핵심 운영 활동입니다. CPU limits 제거로 스로틀링을 방지하고, 메모리 limits로 OOM을 막으며, Goldilocks와 Prometheus 메트릭으로 데이터 기반 의사결정을 하면 효율적인 클러스터를 운영할 수 있습니다.
관련 글로 K8s HPA 오토스케일링 심화와 K8s VPA 리소스 자동 튜닝도 함께 참고하세요.