Kubernetes 리소스 관리 핵심 전략

Kubernetes requests/limits와 QoS로 OOMKilled·CPU throttling을 줄이는 실무 가이드 커버 이미지
Kubernetes 리소스 설계: Requests/Limits, QoS, OOMKilled, CPU throttling | 직접 생성. 무단 사용 금지

쿠버네티스 운영에서 장애가 “에러율”이 아니라 지연(p95/p99)로 먼저 드러나는 경우가 많습니다. 그 출발점이 의외로 단순한데, 바로 CPU/메모리 Requests/Limits를 어떻게 잡았는지입니다.

이 글은 Kubernetes 공식 문서의 정의를 기준으로, 운영자가 실제로 결정을 내려야 하는 지점(스케줄링, 쓰로틀링, OOMKilled, 노드 압박(eviction), QoS)을 한 장의 의사결정 규칙으로 정리합니다. 추정/허구 없이, 근거는 모두 Kubernetes 공식 문서 링크로만 확정합니다.

TL;DR (운영 의사결정 6줄 요약)

  • Requests는 kube-scheduler가 노드에 “올릴 수 있는지”를 판단하는 기준입니다. (스케줄링/용량계획)
  • Limits는 kubelet/컨테이너 런타임이 커널 cgroups로 “넘기면 어떻게 되는지”를 결정합니다. (런타임 거동)
  • CPU limit은 커널이 throttling으로 강제합니다. (죽지는 않지만 느려질 수 있음)
  • Memory limit은 메모리 압박 시 커널의 OOM kill로 종료될 수 있습니다. (재시작 루프 가능)
  • QoS(Guaranteed/Burstable/BestEffort)는 노드 자원 압박 시 eviction 우선순위에 영향을 줍니다.
  • 실무에서는 “Requests는 보수적으로, CPU limit은 서비스 성격에 따라, Memory limit은 스파이크를 감안”이 기본 출발점입니다.

1) Requests vs Limits: Kubernetes가 실제로 어떻게 쓰는가

Kubernetes 공식 문서에서 Requests/Limits의 역할은 명확히 나뉩니다.

  • 컨테이너에 resource request를 지정하면, kube-scheduler가 그 값을 기반으로 파드를 어느 노드에 배치할지 결정합니다.
  • resource limitkubelet이 컨테이너 런타임에 전달하고, 최종적으로 Linux 커널이 cgroups로 제한을 집행합니다.

운영 관점의 핵심 2가지

  • Requests는 “예약”에 가깝고, 노드에 파드를 올릴 수 있는지(스케줄링)와 노드 수 산정에 직접 영향을 줍니다.
  • Limits는 “장애 모드”를 결정합니다. CPU는 throttling, 메모리는 OOM kill 가능성이 커집니다.

2) CPU: 왜 limit이 걸리면 “에러 없이 느려지나”

Kubernetes 문서에 따르면 CPU limit은 커널이 CPU throttling으로 집행합니다. 즉, 컨테이너가 limit에 접근하면 커널이 해당 cgroup의 CPU 사용을 제한합니다. (하드 상한)

CPU request는 무엇을 의미하나 (공식 문서 기준)

Kubernetes 문서는 CPU request를 “가중치(weighting)”로 설명합니다. 여러 cgroup이 CPU를 원할 때 request가 큰 쪽이 더 많은 CPU 시간을 할당받는 식으로 작동할 수 있습니다.

3) Memory: limit이 “즉시”가 아니라 “압박 시” 반응적으로 집행되는 이유

메모리 limit은 CPU와 동일하게 “항상 즉시” 강제되는 방식이 아니라, 문서에서 메모리 압박이 감지될 때 OOM kill로 종료될 수 있다고 설명합니다. 따라서 “limit을 넘는 순간 바로 죽는다”라기보다, 운영에서는 스파이크 + 노드 상황에 따라 종료 타이밍이 달라질 수 있다는 점이 중요합니다.

  • 공식 근거: Resource Management의 “memory limits are enforced … with out of memory (OOM) kills” 및 “memory limits are enforced reactively” 설명
  • 실습/예제 근거: Assign Memory Resources의 OOMKilled 반복 예시

4) QoS(Guaranteed/Burstable/BestEffort): 노드 압박(eviction)에서 ‘누가 먼저 나가나’

Kubernetes는 파드에 대해 QoS 클래스를 부여하고, 이 분류를 노드 자원 압박 시 eviction 의사결정에 활용한다고 문서에 명시합니다.

Guaranteed의 요건(공식 문서 그대로)

Guaranteed QoS는 “각 컨테이너의 CPU/메모리 request와 limit이 모두 존재하며, 서로 값이 동일”해야 부여됩니다.

Burstable의 함정: limit을 빼면 ‘노드 용량’이 기본 limit이 될 수 있다

QoS 문서에는 Burstable 파드에서 limit이 없으면 “노드 용량에 해당하는 limit이 기본값이 된다”는 설명이 있습니다. 즉, limit 미지정이 항상 “무제한” 느낌으로만 작동하는 게 아니라, 노드 환경/정책(LimitRange 등)과 결합해 거동이 달라질 수 있습니다.

5) (필수 보강요소 #1) 운영 체크리스트: 배포 전에 이것만 확인해도 장애가 준다

  1. Pod가 Pending으로 쌓이는가? → Requests 합이 노드 capacity를 넘는지 확인 (스케줄링은 Requests 기준).
  2. p95/p99 지연이 튀는데 에러는 없다? → CPU limit throttling 가능성(공식 문서: CPU limit은 throttling).
  3. OOMKilled 재시작 루프가 있는가? → Memory limit이 스파이크를 못 버티는지 확인 (공식 문서/예제: OOMKilled).
  4. 노드 압박 시 어떤 파드가 먼저 eviction 되는가? → QoS class(Guaranteed/Burstable/BestEffort) 확인.
  5. limit/request 미지정이 섞여 있는가? → QoS가 BestEffort로 떨어지거나, Burstable로 예상치 못한 거동을 만들 수 있음.

6) (필수 보강요소 #2) YAML 예시: “정답”이 아니라 ‘의도’를 드러내는 템플릿

아래는 공식 문서의 필드 구조를 따르는 예시입니다. 수치는 환경마다 다르므로, 이 예시는 구조와 의도를 보여주는 용도입니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: example.com/api:1.0.0
          resources:
            requests:
              cpu: "500m"     # 스케줄링/용량계획의 기준 (kube-scheduler가 사용)
              memory: "512Mi" # 스케줄링에서 중요한 기준
            limits:
              cpu: "1"        # 커널이 throttling으로 강제 (지연 민감 서비스면 신중)
              memory: "768Mi" # 메모리 압박 시 OOM kill 후보가 될 수 있음

필드 의미와 작동은 Kubernetes 공식 문서의 Requests/Limits 정의와 일치합니다.

7) (필수 보강요소 #3) 트러블슈팅 매트릭스: 증상 → 원인 후보 → 확인 포인트

증상 공식 문서 기반 원인 후보 우선 확인
에러 없이 느려짐(p95/p99 악화) CPU limit → throttling (커널 강제) CPU limit throttling 설명
컨테이너가 OOMKilled로 재시작 Memory limit 초과 시 OOM kill 후보 OOMKilled 예제
파드가 Pending에서 멈춤 스케줄러는 Requests 합이 노드 capacity 이하인지 검사 Insufficient cpu 예제
노드 압박 시 특정 파드부터 내려감 QoS class에 따라 eviction 우선순위 영향 QoS와 eviction

8) (필수 보강요소 #4) FAQ: 현장에서 자주 나오는 질문 5개

Q1. CPU limit을 꼭 걸어야 하나요?

필수 규칙은 아닙니다. Kubernetes 문서는 CPU limit이 없을 때 “상한이 없거나, 네임스페이스에 default limit이 있으면 자동 할당”될 수 있다고 설명합니다. 즉, 조직 정책(LimitRange)까지 함께 보고 결정하는 게 안전합니다. (공식 근거: CPU 리소스 할당 문서의 “If you do not specify a CPU limit”)

공식 문서: Assign CPU Resources

Q2. Memory limit만 걸면 안전해지나요?

반대로, 너무 타이트한 memory limit은 OOMKilled 재시작 루프를 만들 수 있습니다. Kubernetes 문서의 예제처럼 limit을 넘으면 컨테이너가 종료되고(재시작 가능), 반복될 수 있습니다.

공식 문서: Assign Memory Resources

Q3. request만 있고 limit이 없으면 QoS는 어떻게 되나요?

QoS는 request/limit의 조합으로 결정됩니다. Guaranteed는 request=limit이 필수이고, 그렇지 않으면 Burstable/BestEffort 쪽으로 분류됩니다. 정확한 분류 기준은 QoS 공식 문서의 “Criteria”를 기준으로 판단하면 됩니다.

공식 문서: Pod QoS

Q4. Requests는 “보수적으로 크게” 잡는 게 맞나요?

Requests를 크게 잡으면 스케줄링이 더 보수적으로 되어 Pending이 늘 수 있고, 작게 잡으면 과밀 스케줄링으로 피크 시 지연이 커질 수 있습니다. 문서가 말하는 핵심은 “스케줄링은 Requests 기준”이라는 점이며, 결국 운영 목표(비용 vs 안정성)에 맞춘 선택입니다.

공식 문서: Resource Management

Q5. Requests/Limits는 어디까지 “쿠버네티스”가 보장하나요?

문서 기준으로, kubelet은 요청/제한을 런타임에 전달하고, Linux에서는 커널 cgroups가 최종 집행합니다. 즉, 동작의 바닥은 커널 레벨에 있습니다.

공식 문서: How Kubernetes applies requests and limits

9) 다음 글 예고 (인접 심화 주제)

  • LimitRange/ResourceQuota로 “조직 기본값”을 강제할 때 생기는 운영 패턴
  • 프로브(readiness/liveness/startupProbe)와 리소스 조정이 롤아웃 실패를 만드는 메커니즘

참고(공식 문서 원문)


CTA: 운영 기준(리소스/QoS/eviction)을 문서로 고정해드릴 수 있습니다

Requests/Limits는 “수치 조정”이 아니라 장애 모드와 비용 구조를 결정하는 설계입니다. 팀 내 기준(예: 지연 민감 서비스는 CPU limit 정책을 어떻게 할지, memory limit headroom을 어떻게 둘지, QoS를 어디까지 Guaranteed로 가져갈지)을 문서로 정리하고, 실제 배포/모니터링 루틴까지 연결하면 운영이 훨씬 단단해집니다.

필요하시면 문의 페이지에 현재 상황(서비스 유형, 장애 증상, 클러스터 규모)을 남겨주세요.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux