Scheduling - Resource Limit

2025. 12. 29. 20:54·CKA

쿠버네티스에서 파드가 어느 노드에 배치될지는 스케줄러가 결정하는데, 이때 가장 중요한 입력 중 하나가 컨테이너의 리소스 요청(Requests) 입니다. 실행 중에는 리소스 제한(Limits) 이 컨테이너의 자원 폭주를 제어합니다.
여기에 더해, 조직/실습 환경에서는 기본값 강제(LimitRange), 네임스페이스 총량 제한(ResourceQuota) 로 정책을 걸어 둡니다. 마지막으로 CKA에서 자주 나오는 Pod 편집 불가 필드와 우회 편집 패턴(kubectl edit) 까지 같이 정리합니다.


1) 스케줄러는 “Requests”를 보고 노드를 고른다

클러스터에 노드가 여러 개 있고 각 노드에 남아있는 CPU/메모리가 다르다고 합시다. 파드가 생성되면 스케줄러는:

  • 파드(정확히는 컨테이너)가 요청한 리소스(Requests)
  • 각 노드의 가용 리소스

를 비교해서 “올릴 수 있는 노드”를 찾습니다.

노드에 충분한 리소스가 없으면?

  • 어떤 노드에도 requests를 만족할 자원이 없으면 파드는 Pending 상태로 남습니다.
  • 원인은 이벤트로 확인합니다.
kubectl get pod -o wide
kubectl describe pod <pod-name>

Events에서 흔히 보이는 메시지:

  • Insufficient cpu
  • Insufficient memory

2) Requests: “최소 보장”이자 “스케줄링 기준”

Requests는 “이 컨테이너는 최소한 이 정도 CPU/메모리는 필요하다”라는 선언입니다.

  • 스케줄러는 requests 합을 보고 노드를 선택합니다.
  • 파드가 노드에 배치되면, 그 requests 만큼은 보장받는다고 이해하면 됩니다(기본 개념).

예시: requests 지정

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: nginx:1.27
    resources:
      requests:
        cpu: "2"
        memory: "4Gi"

3) CPU 단위: vCPU와 milliCPU

CPU는 milliCPU(m) 단위가 실전 표준

  • 100m = 0.1 CPU
  • 500m = 0.5 CPU
  • 1 = 1 CPU

예:

requests:
  cpu: "100m"

클라우드 환경에서는 보통 “1 CPU ≈ 1 vCPU”로 이해해도 운영 판단에 충분합니다.


4) 메모리 단위: Mi/Gi(2진) vs M/G(10진)

이 부분은 실무에서 헷갈리기 쉬운 핵심입니다.

  • Mi, Gi: 2진(1024) 기반
    • 1Gi = 1024Mi
  • M, G: 10진(1000) 기반
    • 1G = 1000M

그래서 “비슷해 보여도 실제 바이트 수가 다름”이 생깁니다. 보통 쿠버네티스 리소스 표기는 Mi, Gi를 많이 씁니다.

requests:
  memory: "256Mi"
# 또는
requests:
  memory: "1Gi"

5) Limits: “최대 상한” (실행 중 폭주 방지)

기본적으로 컨테이너는 (요청/제한이 없다면) 노드 자원을 가능한 만큼 쓰려 할 수 있습니다. 그래서 Limits로 상한을 둡니다.

resources:
  requests:
    cpu: "500m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "512Mi"

중요:

  • requests/limits는 Pod 단위가 아니라 컨테이너 단위
  • 컨테이너가 여러 개면 각 컨테이너별로 설정 가능

6) 한도를 넘으면? CPU와 메모리는 동작이 다르다

CPU: 초과하면 스로틀링(throttling)

  • CPU는 limit을 넘지 못하도록 커널/런타임이 속도를 제한합니다.
  • 파드는 보통 죽지 않고 “느려짐/지연”으로 나타납니다.

메모리: 초과하면 OOMKilled

메모리는 CPU처럼 스로틀링이 어려워서, limit을 지속적으로 넘기면:

  • 컨테이너/파드가 종료될 수 있고
  • 상태에서 OOMKilled가 보입니다.
kubectl describe pod <pod-name>
kubectl logs <pod-name> --previous

7) “Requests/Limits 조합”에 따른 대표 시나리오

(A) requests 없음, limits 없음

  • 스케줄러가 참고할 “최소 요구량”이 없음
  • 어떤 파드가 자원을 독점해 다른 파드를 질식시킬 수 있음

(B) requests 없음, limits만 있음

  • 중요한 포인트: request를 생략하고 limit만 설정하면 request가 limit과 동일하게 잡히는 경우가 많습니다.
  • 결과적으로 스케줄링이 필요 이상으로 빡빡해져 Pending이 늘 수 있음

(C) requests + limits 둘 다 있음

  • 최소 보장 + 최대 상한
  • 단, CPU 상한이 너무 타이트하면 한 파드가 놀고 있어도 다른 파드가 더 못 쓰는 비효율이 생길 수 있음

(D) requests만 있고 limits 없음 (CPU에서 특히 자주 권장)

  • 요청으로 최소 보장을 주고
  • 노드에 여유가 있으면 더 쓰게(특히 CPU)
  • 다른 파드가 필요해지면 requests만큼은 보장되므로 굶김이 줄어듦

운영 정책에 따라 “메모리는 limit을 두고 CPU는 limit을 안 두는” 형태도 흔합니다.


8) 기본값 강제: LimitRange (네임스페이스 단위)

“매번 매니페스트에 requests/limits를 적기 어렵다”면 네임스페이스에 기본값을 강제할 수 있습니다.

여기서 사용자가 헷갈린 포인트: 왜 CPU에 4개가 있나?

LimitRange는 Request와 Limit을 각각 다뤄야 해서 4개가 나옵니다.

  • defaultRequest: requests 기본값(안 적으면 자동으로 들어감)
  • default: limits 기본값(안 적으면 자동으로 들어감)
  • min: requests로 설정 가능한 최소치(너무 작게 “무임승차” 방지)
  • max: limits로 설정 가능한 최대치(오용/독점 방지)

즉,

  • 기본값 2개(요청/한도) + 경계값 2개(요청 최소/한도 최대) 입니다.

예시: CPU LimitRange

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraints
  namespace: default
spec:
  limits:
  - type: Container
    default:
      cpu: "500m"
    defaultRequest:
      cpu: "500m"
    max:
      cpu: "1"
    min:
      cpu: "100m"

메모리도 동일 패턴으로 만들 수 있습니다.

중요:

  • LimitRange는 생성/변경 이후에 새로 생성되는 파드에만 적용됩니다.
  • 기존 파드에는 소급 적용되지 않습니다.

9) 네임스페이스 총량 제한: ResourceQuota

“이 네임스페이스에서 모든 파드를 합쳐 CPU/메모리를 이 이상 못 쓰게” 하고 싶으면 ResourceQuota를 씁니다.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: default
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "4Gi"
    limits.cpu: "10"
    limits.memory: "10Gi"
  • requests 총합, limits 총합을 각각 제한할 수 있습니다.

10) CKA 실전: Pod 편집(Edit) 규칙과 우회 방법

10-1. “실행 중인 Pod에서” 수정 가능한 spec은 매우 제한적

기억해야 할 것: 기존 Pod에서 아래 항목만 수정 가능합니다.

  • spec.containers[*].image
  • spec.initContainers[*].image
  • spec.activeDeadlineSeconds
  • spec.tolerations

즉, 아래는 직접 편집 불가(대표 예):

  • env(환경변수)
  • serviceAccount
  • resource requests/limits
  • 여러 spec 필드들

10-2. kubectl edit로 시도하면?

kubectl edit pod <pod-name>

에디터(보통 vi)로 열리고 수정은 할 수 있지만, 저장 시 수정 불가 필드면 거부(denied) 됩니다.

이때 중요한 동작:

  • 변경본은 임시 파일(/tmp/...)로 저장됩니다.
  • 그 파일을 이용해 “새 Pod를 만들기”로 우회할 수 있습니다.

옵션 1) edit → 거부 → 임시 파일로 재생성

  1. 편집 시도:
kubectl edit pod webapp
  1. 저장 시 거부되면, 출력에 표시된 임시 파일 경로를 확인
  2. 기존 Pod 삭제:
kubectl delete pod webapp
  1. 임시 파일로 새 Pod 생성:
kubectl create -f /tmp/kubectl-edit-ccvrq.yaml

옵션 2) get -o yaml로 내보내고 수정 후 재생성

  1. YAML 추출:
kubectl get pod webapp -o yaml > my-new-pod.yaml
  1. 파일 수정:
vi my-new-pod.yaml
  1. 기존 Pod 삭제:
kubectl delete pod webapp
  1. 수정본으로 생성:
kubectl create -f my-new-pod.yaml

시험 팁: 단독 Pod는 “대부분 수정 불가 → 삭제 후 재생성”이 더 빠른 경우가 많습니다.


11) Deployment는 edit가 훨씬 쉽다 (Pod 템플릿 수정)

Deployment는 Pod가 “자식 리소스”라서, 템플릿을 바꾸면 컨트롤러가 자동으로 롤아웃합니다.

  • Deployment의 spec.template는 원하는 필드를 대부분 수정 가능
  • 수정하면 Deployment가 새 ReplicaSet/새 Pod를 만들어 교체(롤링 업데이트)
kubectl edit deployment my-deployment

시험에서 “Deployment가 만든 Pod의 어떤 속성을 바꿔라”가 나오면,
대부분은 Pod를 직접 만지지 말고 Deployment를 edit하는 게 정답 루트입니다.


정리

  • Requests는 스케줄러의 핵심 입력(최소 보장/배치 기준)
  • Limits는 실행 중 상한(CPU=스로틀링, Memory=OOMKilled)
  • 기본값/정책 강제는 LimitRange(컨테이너 기본/범위), 총량 제한은 ResourceQuota(네임스페이스 총합)
  • 기존 Pod에서 수정 가능한 spec은 극히 제한(이미지/activeDeadlineSeconds/tolerations 등)
  • 수정이 필요하면 삭제 후 재생성 또는 Deployment 템플릿 수정(edit deployment) 이 정석

'CKA' 카테고리의 다른 글

Scheduling - Static Pod  (0) 2025.12.29
Scheduling- DaemonSet  (0) 2025.12.29
Scheduling - Node Selector & Node Affinity  (0) 2025.12.29
Scheduling - Taint & Toleration  (0) 2025.12.29
Scheduling- Label & Selector  (0) 2025.12.29
'CKA' 카테고리의 다른 글
  • Scheduling - Static Pod
  • Scheduling- DaemonSet
  • Scheduling - Node Selector & Node Affinity
  • Scheduling - Taint & Toleration
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      페치 조인
      단방향 맵핑
      @args
      WAS
      락
      Target
      hibernate5module
      requset scope
      gesingleresult
      Thread
      양방향 맵핑
      typequery
      @discriminatorcolumn
      reentarantlock
      고급
      @within
      버퍼
      빈 후처리기
      JPQL
      조회 성능 최적화
      프록시
      @discriminatorvalue
      jpq
      김영한
      프록시 팩토리
      cglib
      log trace
      jdk 동적 프록시
      스레드
      자바
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Scheduling - Resource Limit
    상단으로

    티스토리툴바