Pod 가 Pending 에서 움직이지 않고 이벤트에 다음이 남는다.
Warning FailedScheduling ... 0/3 nodes are available: 3 Insufficient cpu.
"서버 코어 수를 넘었다" 는 이해는 절반만 맞다. 스케줄러가 보는 것은 노드의 allocatable CPU 에서 이미 다른 Pod 들이 예약해 간 requests 를 뺀 나머지다. 실제 사용률은 보지 않는다. 그래서 CPU 사용률이 5% 인 노드에서도 Insufficient cpu 가 난다. 예약만 해 놓고 쓰지 않는 Pod 가 자리를 차지하고 있으면 그렇다.
allocatable 은 물리 코어 수보다 작다. kubelet 과 시스템 데몬 몫(--kube-reserved · --system-reserved · eviction 임계치) 이 빠지기 때문이다.
kubectl describe node <노드>
출력의 Allocatable 과 Allocated resources 를 본다. cpu 행의 Requests 백분율이 100% 에 가까우면 예약이 꽉 찬 것이다.
kubectl describe pod <파드> | sed -n '/Events/,$p'
kubectl get pod <파드> -o jsonpath='{.spec.containers[*].resources}'
메시지 앞의 0/N nodes are available 에서 N 이 전체 노드 수다. 3 중 3 이 Insufficient cpu 라면 모든 노드에서 CPU 가 원인이고, 2 Insufficient cpu, 1 node(s) had untolerated taint 처럼 섞여 나오면 노드마다 이유가 다르다는 뜻이다.
요청량이 과하지 않은지 본다. resources.requests.cpu 는 "이만큼은 보장받아야 한다" 는 값이지 최대치가 아니다. 최대치는 limits 다. 요청을 실제 정상 부하의 평균 수준으로 낮추면 대부분 해결된다. 1000m 을 요청하면서 평균 50m 을 쓰고 있다면 요청이 잘못 잡힌 것이다.
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
자리를 먹고 있는 Pod 를 찾는다.
kubectl get pods -A -o custom-columns=\
NS:.metadata.namespace,NAME:.metadata.name,NODE:.spec.nodeName,\
CPU:.spec.containers[*].resources.requests.cpu --sort-by=.spec.nodeName
노드를 늘리거나 키운다. 예약 총량이 실제로 필요한 양이라면 이것이 정답이다. Cluster Autoscaler 를 쓰고 있다면 왜 확장이 안 됐는지(최대 노드 수·인스턴스 쿼터) 를 본다.
컨트롤 플레인 노드를 워커로 쓰는 것은 마지막 수단이다. 단일 노드나 실습 클러스터가 아니라면 taint 를 풀지 않는다.
kubectl taint nodes <노드> node-role.kubernetes.io/control-plane:NoSchedule-
requests 를 0 이나 지나치게 작게 두면 스케줄은 되지만 노드가 과다 예약(over-subscribe) 되어 CPU 쓰로틀링과 지연이 생긴다. 스케줄이 목적이 아니라 실제 필요량을 맞추는 것이 목적이다. LimitRange 나 ResourceQuota 가 걸려 있는 네임스페이스라면 값을 바꾸기 전에 그 제약부터 확인한다.