K8s ResourceQuota·LimitRange 운영

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의 defaultdefaultRequest는 리소스를 명시하지 않은 컨테이너에 자동으로 주입됩니다. 이는 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를 자동 포함하세요
위로 스크롤
WordPress Appliance - Powered by TurnKey Linux