쿠버네티스에서 파드가 어느 노드에 배치될지는 스케줄러가 결정하는데, 이때 가장 중요한 입력 중 하나가 컨테이너의 리소스 요청(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 cpuInsufficient 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.1CPU500m=0.5CPU1= 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[*].imagespec.initContainers[*].imagespec.activeDeadlineSecondsspec.tolerations
즉, 아래는 직접 편집 불가(대표 예):
- env(환경변수)
- serviceAccount
- resource requests/limits
- 여러 spec 필드들
10-2. kubectl edit로 시도하면?
kubectl edit pod <pod-name>
에디터(보통 vi)로 열리고 수정은 할 수 있지만, 저장 시 수정 불가 필드면 거부(denied) 됩니다.
이때 중요한 동작:
- 변경본은 임시 파일(/tmp/...)로 저장됩니다.
- 그 파일을 이용해 “새 Pod를 만들기”로 우회할 수 있습니다.
옵션 1) edit → 거부 → 임시 파일로 재생성
- 편집 시도:
kubectl edit pod webapp
- 저장 시 거부되면, 출력에 표시된 임시 파일 경로를 확인
- 기존 Pod 삭제:
kubectl delete pod webapp
- 임시 파일로 새 Pod 생성:
kubectl create -f /tmp/kubectl-edit-ccvrq.yaml
옵션 2) get -o yaml로 내보내고 수정 후 재생성
- YAML 추출:
kubectl get pod webapp -o yaml > my-new-pod.yaml
- 파일 수정:
vi my-new-pod.yaml
- 기존 Pod 삭제:
kubectl delete pod webapp
- 수정본으로 생성:
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 |