전체 비유: 아파트 전기/수도 배정#

리소스 관리를 아파트 전기/수도 배정에 비유하면 이해하기 쉽습니다:

아파트 공과금 비유Kubernetes역할
기본 전기 용량requests최소 보장 리소스
최대 전기 용량limits사용 가능한 최대치
전기 초과 시 차단기CPU 스로틀링한계 초과 시 성능 저하
수도 초과 시 단수OOMKilled메모리 초과 시 강제 종료
프리미엄 세대Guaranteed QoS가장 마지막에 퇴거 요청
일반 세대Burstable QoS중간 우선순위
관리비 미납 세대BestEffort QoS가장 먼저 퇴거 요청
단지 전체 전기 한도ResourceQuota네임스페이스 총량 제한
세대별 기본 배정량LimitRange기본 리소스 설정

이처럼 requests는 “항상 보장받는 기본 전기량"이고, limits는 “절대 넘을 수 없는 최대 사용량"입니다.


대상 독자: Kubernetes에서 리소스를 효율적으로 관리하고 싶은 백엔드 개발자 선수 지식: Pod, Deployment 개념 소요 시간: 약 25-30분 이 문서를 읽으면: requests와 limits의 차이, 적절한 리소스 설정 방법을 이해할 수 있습니다

TL;DR
  • requests: 스케줄링에 사용되는 최소 보장 리소스
  • limits: 사용 가능한 최대 리소스
  • CPU 초과 시 스로틀링, 메모리 초과 시 OOMKilled

왜 리소스 설정이 필요한가?#

리소스 설정 없이 Pod를 실행하면 여러 문제가 발생합니다.

문제리소스 설정 후
한 Pod가 노드 리소스 독점limits로 최대 사용량 제한
스케줄링 시 리소스 고려 안 됨requests 기반 스케줄링
메모리 부족 시 임의 Pod 종료QoS 클래스 기반 우선순위
리소스 사용량 예측 불가명시적 리소스 할당

requests와 limits#

Kubernetes는 두 가지 리소스 제어 방식을 제공합니다.

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"
flowchart LR
    subgraph Resources
        REQ[requests: 256Mi]
        USE[실제 사용량]
        LIM[limits: 512Mi]
    end
    REQ -->|보장| USE
    USE -->|제한| LIM

requests와 limits를 비교하면 다음과 같습니다.

항목requestslimits
역할최소 보장량최대 허용량
스케줄링기준으로 사용사용 안 함
실행 중항상 사용 가능초과 시 제한
미설정 시limits와 동일무제한

CPU 리소스#

CPU는 압축 가능한(compressible) 리소스입니다. 초과해도 스로틀링될 뿐 종료되지 않습니다.

CPU 단위#

표기의미예시
11 vCPUcpu: 1
1000m1 vCPUcpu: 1000m
500m0.5 vCPUcpu: 500m
100m0.1 vCPUcpu: 100m

m은 밀리코어(millicores)를 의미합니다. 1000m = 1 CPU입니다.

CPU 동작#

flowchart LR
    subgraph "requests: 250m"
        A[Pod A]
    end
    subgraph "requests: 500m"
        B[Pod B]
    end
    CPU[1 CPU]
    A -->|보장 250m| CPU
    B -->|보장 500m| CPU
    CPU -->|남은 250m| C[경합]
상황동작
전체 사용량 < 노드 용량모든 Pod가 필요한 만큼 사용
전체 사용량 > 노드 용량requests 비율에 따라 분배
Pod 사용량 > limitsCPU 스로틀링 (성능 저하)

메모리 리소스#

메모리는 압축 불가능한(incompressible) 리소스입니다. 초과하면 Pod가 종료(OOMKilled)됩니다.

메모리 단위#

표기의미
256Mi256 메비바이트 (256 × 2^20 bytes)
1Gi1 기비바이트 (1 × 2^30 bytes)
256M256 메가바이트 (256 × 10^6 bytes)
1G1 기가바이트 (1 × 10^9 bytes)
Mi vs M
Mi(메비바이트)는 2^20 bytes, M(메가바이트)는 10^6 bytes입니다. Kubernetes에서는 보통 Mi, Gi를 사용합니다.

메모리 동작#

상황동작
사용량 < requests정상 실행
requests < 사용량 < limits정상 실행 (노드 여유 있으면)
사용량 > limitsOOMKilled (컨테이너 재시작)
노드 메모리 부족QoS 클래스 기반 종료

QoS 클래스#

Kubernetes는 리소스 설정에 따라 Pod에 QoS(Quality of Service) 클래스를 할당합니다.

클래스조건우선순위
Guaranteed모든 컨테이너에 requests=limits최고 (가장 마지막에 종료)
Burstablerequests < limits 또는 일부만 설정중간
BestEffort리소스 설정 없음최저 (가장 먼저 종료)
# Guaranteed
resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "256Mi"
    cpu: "250m"

# Burstable
resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

# BestEffort (리소스 설정 없음)
# resources: {}

노드 메모리가 부족할 때 종료 순서는 다음과 같습니다.

flowchart LR
    M[메모리 부족] --> BE[BestEffort 먼저 종료]
    BE --> BU[Burstable 종료]
    BU --> GU[Guaranteed 마지막]

권장 설정#

워크로드 유형별 권장 설정#

실제 운영에서 자주 사용되는 워크로드 유형별 시작점입니다.

워크로드requests (CPU/Mem)limits (CPU/Mem)특징
Spring Boot API250m / 512Mi1000m / 1GiJVM 힙 고려
Node.js API100m / 128Mi500m / 256Mi가벼움
Python Flask100m / 128Mi500m / 512MiML 라이브러리 시 증가
Nginx (프록시)50m / 64Mi200m / 128Mi매우 가벼움
Redis (캐시)100m / 256Mi500m / 512Mi메모리 중심
Batch Job500m / 512Mi2000m / 2Gi처리량 중심
주의
위 값은 시작점입니다. 실제 사용량을 모니터링(kubectl top pods)하여 조정하세요.

Java 애플리케이션#

resources:
  requests:
    memory: "512Mi"
    cpu: "250m"
  limits:
    memory: "1Gi"
    cpu: "1000m"

Java 애플리케이션 특성상 메모리 limits는 넉넉히 설정하되, JVM 힙 사이즈도 함께 조정해야 합니다.

env:
- name: JAVA_OPTS
  value: "-Xms256m -Xmx768m"

JVM 힙은 컨테이너 메모리 limits의 70-80%로 설정하는 것이 일반적입니다.

리소스 설정 가이드라인#

항목권장 사항
requests평상시 사용량의 90%
limits (CPU)requests의 2-4배 또는 미설정
limits (메모리)requests의 1.5-2배
Guaranteed중요 워크로드에 사용

LimitRange#

네임스페이스 수준에서 기본 리소스 제한을 설정합니다.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
spec:
  limits:
  - default:          # 기본 limits
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:   # 기본 requests
      cpu: "100m"
      memory: "128Mi"
    max:              # 최대 허용
      cpu: "2"
      memory: "2Gi"
    min:              # 최소 허용
      cpu: "50m"
      memory: "64Mi"
    type: Container

리소스를 명시하지 않은 Pod에 기본값이 적용됩니다.

ResourceQuota#

네임스페이스 전체의 리소스 총량을 제한합니다.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    pods: "10"

이 설정은 해당 네임스페이스에서 다음을 제한합니다.

항목제한
CPU requests 합계4 코어
메모리 requests 합계8Gi
최대 Pod 수10개

실습: 리소스 설정과 확인#

리소스 사용량 확인#

# 노드 리소스 확인
kubectl describe node <node-name>

# Pod 리소스 사용량 (metrics-server 필요)
kubectl top pods
kubectl top nodes

리소스 부족 시뮬레이션#

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
spec:
  containers:
  - name: memory-demo
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
# Pod 생성
kubectl apply -f memory-demo.yaml

# 상태 확인 (OOMKilled 발생)
kubectl get pod memory-demo
kubectl describe pod memory-demo

QoS 클래스 확인#

kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'

다음 단계#

리소스 관리를 이해했다면 다음 단계로 진행하세요:

목표추천 문서
자동 스케일링스케일링
헬스 체크 설정헬스 체크
리소스 최적화리소스 최적화