ResourceQuota와 LimitRange란?
멀티 테넌트 Kubernetes 클러스터에서 특정 네임스페이스가 리소스를 독점하면 다른 워크로드에 영향을 줍니다. ResourceQuota는 네임스페이스 단위로 총 리소스 사용량을 제한하고, LimitRange는 개별 파드/컨테이너의 리소스 기본값과 범위를 설정합니다. 이 두 리소스를 조합하면 클러스터 리소스를 공정하게 분배하고, 무한 스케일링이나 리소스 누수를 방지할 수 있습니다.
ResourceQuota: 네임스페이스 총량 제한
ResourceQuota는 네임스페이스 내에서 생성할 수 있는 리소스의 총량을 제한합니다. CPU, 메모리뿐 아니라 파드 수, 서비스 수, PVC 수 등 오브젝트 카운트도 제한할 수 있습니다.
# 컴퓨트 리소스 쿼터
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: team-backend
spec:
hard:
# CPU/메모리 총량
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
# 파드 수 제한
pods: "50"
# PVC 제한
persistentvolumeclaims: "10"
requests.storage: 100Gi
---
# 오브젝트 카운트 쿼터
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota
namespace: team-backend
spec:
hard:
services: "20"
services.loadbalancers: "2"
services.nodeports: "5"
secrets: "50"
configmaps: "50"
replicationcontrollers: "0" # RC 사용 금지
ResourceQuota 스코프: 조건부 제한
스코프를 지정하면 특정 조건의 파드에만 쿼터를 적용할 수 있습니다. PriorityClass 기반 스코프로 우선순위별 리소스 할당이 가능합니다.
# BestEffort 파드 제한 (requests/limits 미설정 파드)
apiVersion: v1
kind: ResourceQuota
metadata:
name: besteffort-quota
namespace: team-backend
spec:
hard:
pods: "5" # BestEffort 파드는 5개까지만
scopes:
- BestEffort
---
# NotBestEffort 파드 제한 (requests/limits 설정된 파드)
apiVersion: v1
kind: ResourceQuota
metadata:
name: not-besteffort-quota
namespace: team-backend
spec:
hard:
pods: "45"
requests.cpu: "20"
requests.memory: 40Gi
scopes:
- NotBestEffort
---
# PriorityClass 기반 스코프
apiVersion: v1
kind: ResourceQuota
metadata:
name: high-priority-quota
namespace: team-backend
spec:
hard:
pods: "10"
requests.cpu: "10"
requests.memory: 20Gi
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values: ["high-priority"]
| 스코프 | 대상 파드 | 적용 가능 리소스 |
|---|---|---|
BestEffort |
QoS가 BestEffort인 파드 | pods만 |
NotBestEffort |
QoS가 Burstable 또는 Guaranteed | pods, CPU, 메모리 |
Terminating |
activeDeadlineSeconds 설정된 파드 | pods, CPU, 메모리 |
NotTerminating |
activeDeadlineSeconds 미설정 파드 | pods, CPU, 메모리 |
LimitRange: 개별 파드/컨테이너 제한
LimitRange는 네임스페이스 내 개별 컨테이너, 파드, PVC에 대한 리소스 기본값, 최솟값, 최댓값을 설정합니다. ResourceQuota가 “전체 파이”를 제한한다면, LimitRange는 “한 조각의 크기”를 제한합니다.
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: team-backend
spec:
limits:
# 컨테이너 레벨 제한
- type: Container
default: # limits 기본값 (미설정 시 자동 적용)
cpu: 500m
memory: 512Mi
defaultRequest: # requests 기본값
cpu: 100m
memory: 128Mi
max: # 최대 허용
cpu: "4"
memory: 4Gi
min: # 최소 허용
cpu: 50m
memory: 64Mi
maxLimitRequestRatio: # limits/requests 비율 제한
cpu: "4" # limits는 requests의 4배까지만
memory: "4"
# 파드 레벨 제한 (모든 컨테이너 합산)
- type: Pod
max:
cpu: "8"
memory: 8Gi
min:
cpu: 100m
memory: 128Mi
# PVC 스토리지 크기 제한
- type: PersistentVolumeClaim
max:
storage: 50Gi
min:
storage: 1Gi
LimitRange default 동작 이해
LimitRange의 default와 defaultRequest는 리소스를 명시하지 않은 컨테이너에 자동으로 주입됩니다. 이는 ResourceQuota와 함께 사용할 때 특히 중요합니다.
# ResourceQuota가 설정되면 모든 파드에 requests/limits 필수!
# LimitRange default가 없으면 → 파드 생성 거부
# 예시: requests/limits 없이 파드 생성 시도
apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: team-backend
spec:
containers:
- name: app
image: nginx
# resources 미설정
# LimitRange가 있으면 → 자동으로 주입됨:
# resources:
# requests:
# cpu: 100m (defaultRequest)
# memory: 128Mi (defaultRequest)
# limits:
# cpu: 500m (default)
# memory: 512Mi (default)
# LimitRange가 없으면 → 에러 발생:
# Error: must specify limits.cpu, limits.memory
ResourceQuota + LimitRange 조합 전략
실무에서는 두 리소스를 반드시 함께 사용해야 합니다. ResourceQuota 없이 LimitRange만 있으면 파드 수로 리소스 독점이 가능하고, LimitRange 없이 ResourceQuota만 있으면 단일 파드가 쿼터 전체를 점유할 수 있습니다.
# 팀별 네임스페이스 리소스 설계 예시
# team-backend: CPU 20코어, 메모리 40Gi 할당
# 1. 네임스페이스 총량 제한
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: team-backend
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
persistentvolumeclaims: "20"
requests.storage: 200Gi
services.loadbalancers: "3"
---
# 2. 개별 컨테이너 범위 + 기본값 설정
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-backend
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "4"
memory: 8Gi
min:
cpu: 50m
memory: 64Mi
- type: PersistentVolumeClaim
max:
storage: 50Gi
min:
storage: 1Gi
쿼터 모니터링과 알림
쿼터 사용률을 모니터링하여 리소스 부족을 사전에 감지합니다.
# 쿼터 사용량 조회
kubectl describe resourcequota -n team-backend
# Name: team-quota
# Resource Used Hard
# -------- ---- ----
# limits.cpu 12 40
# limits.memory 24Gi 80Gi
# pods 35 100
# requests.cpu 6 20
# requests.memory 12Gi 40Gi
# 사용률 퍼센트로 확인
kubectl get resourcequota -n team-backend -o jsonpath='{
.items[0].status.used.pods}/{.items[0].status.hard.pods}'
# 35/100
# Prometheus 메트릭으로 알림
# kube_resourcequota 메트릭 활용
# 사용률 80% 이상 시 경고 알림:
# kube_resourcequota{type="used"} /
# kube_resourcequota{type="hard"} > 0.8
# LimitRange 확인
kubectl describe limitrange -n team-backend
트러블슈팅 패턴
ResourceQuota/LimitRange 관련 흔한 문제와 해결 방법입니다.
# 문제 1: "forbidden: exceeded quota"
# → 네임스페이스 쿼터 초과
kubectl describe resourcequota -n team-backend
# 해결: 불필요한 파드 정리 또는 쿼터 상향
# 문제 2: "must specify limits"
# → ResourceQuota 있는데 LimitRange 없음
# 해결: LimitRange에 default/defaultRequest 설정
# 문제 3: HPA가 스케일 아웃 안 됨
# → 쿼터 여유분 부족으로 새 파드 생성 불가
# 해결: HPA maxReplicas × 파드 리소스 < 쿼터 hard 확인
# 문제 4: "minimum cpu usage per Container is 50m"
# → LimitRange min 미충족
# 해결: 컨테이너 requests를 min 이상으로 설정
운영 베스트 프랙티스
- 항상 함께 사용: ResourceQuota와 LimitRange는 반드시 세트로 설정하세요 — 하나만으로는 불완전합니다
- LimitRange default 필수: ResourceQuota가 있는 네임스페이스에서는 LimitRange의
default/defaultRequest를 설정해야 파드 생성 거부를 방지합니다 - HPA 연동 시 쿼터 여유: 오토스케일링 maxReplicas까지 스케일 아웃할 수 있도록 쿼터에 여유를 두세요
- maxLimitRequestRatio 설정: limits/requests 비율을 제한하여 과도한 오버커밋을 방지하세요
- Prometheus 알림: 쿼터 사용률 80% 이상 시 경고 알림을 설정하세요
- 네임스페이스 템플릿화: Helm이나 Kustomize로 네임스페이스 생성 시 ResourceQuota + LimitRange를 자동 포함하세요