Kubernetes 스케줄링 오류 설명: 해결 방법 및 모범 사례
Kubernetes 스케줄링 마스터하기! 이 가이드는 Pod가 'Pending' 상태에 갇히는 이유를 명확히 설명합니다. `kubectl describe`를 사용하여 오류를 진단하고, CPU/메모리 부족 문제를 해결하며, Node Affinity 제한을 극복하고, Taints 및 Tolerations를 올바르게 활용하여 강력한 워크로드 배치를 수행하는 방법을 배웁니다.
Kubernetes 스케줄링 오류 설명: 해결 방법 및 모범 사례
Kubernetes 스케줄링 오류는 일반적으로 Pod가 Pending 상태에 멈춰 있는 것으로 나타납니다. 이 상태는 모호하게 느껴질 수 있지만, 특정한 의미를 가지고 있습니다: Kubernetes가 Pod 객체를 수락했지만, 스케줄러가 Pod의 요구 사항을 충족하는 노드를 찾지 못했다는 것입니다. 컨테이너가 충돌한 것이 아닙니다. 앱이 시작되지 않은 것입니다. 많은 경우, 이미지조차 아직 가져오지 않았습니다.
이러한 문제를 해결하는 가장 빠른 방법은 Pod가 요청하는 것과 클러스터가 제공할 수 있는 것을 비교하는 것입니다. CPU 및 메모리 요청, 노드 레이블, 선호도 규칙, 테인트(Taints), 톨러레이션(Tolerations), 퍼시스턴트 볼륨(Persistent Volumes), 토폴로지 분산 규칙(Topology Spread Rules), 네임스페이스 할당량(Quotas)이 모두 배치를 차단할 수 있습니다. 스케줄러는 필수 제약 조건에 대해 엄격합니다. 하나의 필수 규칙이 모든 노드를 제외하면 Pod는 대기합니다.
Pending Pod 진단: 첫 번째 단계
수정을 시도하기 전에 스케줄러가 실패하는 이유를 정확히 진단해야 합니다. 이 조사를 위한 주요 도구는 kubectl describe pod입니다.
Pod가 Pending 상태에 갇혀 있으면, describe 출력의 Events 섹션에 스케줄링 결정 프로세스와 모든 거부에 대한 중요한 정보가 포함되어 있습니다.
kubectl describe pod 사용
항상 문제가 있는 Pod를 대상으로 합니다:
kubectl describe pod <pod-name> -n <namespace>
출력을 검토하고, 특히 하단의 Events 섹션을 살펴보세요. 여기의 메시지는 일반적으로 스케줄링을 방해한 제약 조건을 명시합니다. 일반적인 메시지는 Insufficient cpu, Insufficient memory, 노드 셀렉터 불일치, 용인되지 않은 테인트, 또는 볼륨 바인딩과 관련됩니다.
일반적인 스케줄링 오류 범주 및 해결 방법
스케줄링 실패는 일반적으로 세 가지 주요 범주로 나뉩니다: 리소스 제약 조건, 정책 제약 조건(선호도/반선호도), 및 노드 구성(테인트/톨러레이션).
1. 리소스 제약 조건 (리소스 부족)
이것이 가장 빈번한 원인입니다. 스케줄러는 Pod 사양에 정의된 요청을 충족할 수 있는 노드가 필요합니다. 충분한 할당 가능한 CPU 또는 메모리가 있는 노드가 없으면 Pod는 Pending 상태로 유지됩니다.
문제 식별
Events 섹션에 다음과 같은 메시지가 표시됩니다:
0/3 nodes are available: 3 Insufficient cpu.0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.
이러한 메시지는 결합될 수 있습니다. 첫 번째 구문에서 멈추지 마십시오. 세 노드가 세 가지 다른 이유로 실패하는 경우, 한 가지 이유만 수정하면 Pod가 여전히 보류 상태로 남을 수 있습니다.
리소스 부족에 대한 해결 방법
- Pod 요청 줄이기: Pod 요청이 지나치게 높은 경우 Pod 또는 Deployment YAML에서 CPU 또는 메모리
requests를 낮추십시오. - 클러스터 용량 늘리기: Kubernetes 클러스터에 노드를 더 추가하십시오.
- 기존 워크로드 정리: 중요하지 않은 워크로드를 축소하고, 버려진 작업을 제거하거나, 기존 배포의 과도한 요청을 조정하십시오. 노드 유지 관리를 위해
kubectl drain을 사용하고, 일상적인 정리 명령으로 사용하지 마십시오. - Limit Ranges 사용: 네임스페이스에 정의된 리소스 제한이 없는 경우
LimitRange객체를 구현하여 단일 Pod가 리소스를 독점하는 것을 방지하십시오.
2. 노드 셀렉터 및 선호도/반선호도 규칙
Kubernetes는 nodeSelector, nodeAffinity, podAffinity/podAntiAffinity를 사용하여 Pod를 배치할 수 있거나 배치해야 하는 위치를 세밀하게 제어할 수 있습니다.
노드 셀렉터 불일치
사용 가능한 노드에 있는 레이블과 일치하지 않는 nodeSelector를 정의하면 Pod를 스케줄링할 수 없습니다.
예시 YAML 스니펫 (실패 원인):
spec:
nodeSelector:
disktype: ssd-fast
containers: [...] # disktype=ssd-fast 레이블이 있는 노드가 없으면 Pod는 Pending 상태로 유지됨
해결 방법: nodeSelector에 지정된 레이블이 하나 이상의 노드에 존재하는지 확인하고(kubectl get nodes --show-labels), 대소문자가 정확히 일치하는지 확인하십시오.
클러스터에 레이블이 많은 경우 대상 레이블 검사를 사용하십시오:
kubectl get nodes -L disktype,topology.kubernetes.io/zone
kubectl describe node <node-name>
일반적인 실수는 이전 노드 그룹에는 있었지만 교체 노드 그룹에는 없는 레이블을 사용하는 것입니다. 클러스터 업그레이드 또는 오토스케일링 그룹 마이그레이션 후에는 이전 배치 규칙이 조용히 불가능해질 수 있습니다.
노드 선호도 제약 조건
nodeAffinity는 더 유연한 규칙(예: requiredDuringSchedulingIgnoredDuringExecution 또는 preferredDuringSchedulingIgnoredDuringExecution)을 제공합니다. required 규칙을 충족할 수 없으면 Pod는 Pending 상태로 유지됩니다.
진단 팁: 복잡한 선호도 규칙을 사용할 때 Events 섹션에는 종종 node(s) didn't match node selector.라고 명시됩니다.
Pod 선호도 및 반선호도
이러한 규칙은 다른 Pod를 기준으로 배치를 제어합니다. 예를 들어, 반선호도 규칙이 특정 서비스를 호스팅하는 노드에서 Pod가 실행되지 않도록 요구하지만 모든 노드가 이미 해당 서비스를 호스팅하는 경우 스케줄링이 실패합니다.
해결 방법: 선호도 규칙의 토폴로지 키와 셀렉터를 주의 깊게 검토하십시오. 반선호도 규칙이 너무 제한적인 경우 요구 사항을 완화하거나 규칙이 선택한 대상 Pod가 실제로 피하려는 노드에서 실행 중인지 확인하십시오.
규칙이 하드 요구 사항보다는 선호도를 표현하는 경우 preferredDuringSchedulingIgnoredDuringExecution을 선호하십시오. 필수 반선호도는 중요 서비스의 복제본을 분산하는 데 유용하지만 소규모 클러스터에서는 배포를 차단할 수 있습니다. 예를 들어, 엄격한 구역당 하나의 반선호도를 가진 세 개의 복제본은 사용 가능한 구역이 두 개뿐인 클러스터에서는 깔끔하게 스케줄링할 수 없습니다.
3. 테인트(Taints) 및 톨러레이션(Tolerations)
테인트는 Pod를 밀어내기 위해 노드에 직접 적용되는 반면, 톨러레이션은 Pod 사양에 추가되어 테인트된 노드에 Pod가 들어갈 수 있도록 허용합니다.
- 테인트: 일치하는 톨러레이션이 없으면 Pod를 밀어냅니다.
- 톨러레이션: 일치하는 테인트가 있는 노드에 Pod가 스케줄링되도록 허용합니다.
테인트 거부 식별
Events는 거부 이유를 명시적으로 표시합니다:
0/3 nodes are available: 2 node(s) had taint {dedicated: special-workload, effect: NoSchedule}, that the pod didn't tolerate.
테인트 및 톨러레이션에 대한 해결 방법
두 가지 주요 경로가 있습니다:
Pod 수정 (애플리케이션 Pod에 권장): 노드의 테인트와 일치하는 필수
tolerations를 Pod 사양에 추가하십시오.톨러레이션 예시:
spec: tolerations: - key: "dedicated" operator: "Equal" value: "special-workload" effect: "NoSchedule" containers: [...]노드 수정 (클러스터 관리자에게 권장): 제한이 더 이상 필요하지 않은 경우 노드에서 테인트를 제거하십시오.
# 테인트를 제거하려면 kubectl taint nodes <node-name> dedicated:special-workload:NoSchedule-
모범 사례 경고: 의도적으로 중요한 제어 플레인 구성 요소를 마스터 노드에 스케줄링하지 않는 한, 애플리케이션 Pod에서 전역
node-role.kubernetes.io/master:NoSchedule테인트를 용인하지 마십시오.
최신 클러스터에서 제어 플레인 노드는 일반적으로 이전 마스터 용어 대신 또는 함께 node-role.kubernetes.io/control-plane 테인트를 사용합니다. 이전 매니페스트에서 톨러레이션을 복사하기 전에 실제 테인트를 확인하십시오:
kubectl describe node <node-name> | grep -i taints
고급 스케줄링 제약 조건
덜 일반적이지만 중요한 제약 조건도 스케줄링을 차단할 수 있습니다:
스토리지 볼륨 제약 조건
Pod가 사용 가능한 노드에 바인딩할 수 없는 PersistentVolumeClaim(PVC)을 요청하는 경우(예: 특정 스토리지 프로비저너 요구 사항 또는 볼륨을 사용할 수 없기 때문에) Pod는 Pending 상태로 유지될 수 있습니다.
진단: 먼저 PVC 상태를 확인하십시오(kubectl describe pvc <pvc-name>). PVC가 Pending 상태에 갇혀 있으면 볼륨을 사용할 수 있을 때까지 Pod 스케줄링이 중단됩니다.
StorageClass에서 volumeBindingMode: WaitForFirstConsumer에 의해 스토리지가 의도적으로 지연될 수도 있습니다. 이 모드에서 바인딩은 스케줄러가 적합한 노드를 선택할 때까지 기다립니다. 볼륨이 Pod와 동일한 영역에 생성되어야 할 수 있기 때문입니다. 이는 정상이지만, Pod와 스토리지 제약 조건을 함께 충족하는 노드가 없으면 Pod는 보류 상태로 유지됩니다.
DaemonSets 및 토폴로지 분산
DaemonSets는 선택 기준(있는 경우)과 일치하는 노드에만 스케줄링됩니다. 클러스터가 분할되거나 새 노드가 DaemonSet의 셀렉터와 일치하지 않으면 실행되지 않습니다.
토폴로지 분산 제약 조건(정의된 경우)은 균등한 분배를 보장합니다. 현재 분포가 분산 제약 조건을 존중하면서 노드에 배치하는 것을 방해하면 스케줄링이 실패합니다.
토폴로지 분산 실패는 부분적인 중단 후에 자주 나타납니다. 하나의 영역을 사용할 수 없고 배포에 영역 전체에 엄격한 분산 제약 조건이 있다고 가정해 보겠습니다. Kubernetes는 왜곡 규칙을 위반하기 때문에 나머지 영역에 새 복제본을 배치하는 것을 거부할 수 있습니다. 이 동작은 분산 목표를 보호하지만, 중단 중에는 용량을 복원하기 위해 일시적으로 제약 조건을 완화해야 할 수 있습니다.
네임스페이스 할당량 및 LimitRanges
Pod는 네임스페이스 정책에 의해서도 차단될 수 있습니다. ResourceQuota는 네임스페이스의 총 사용량을 제어합니다. LimitRange는 기본값 또는 최소 및 최대 리소스 값을 설정할 수 있습니다.
Pod 사양이 합리적으로 보이지만 생성 또는 스케줄링이 여전히 실패하는 경우 확인하십시오:
kubectl get resourcequota -n <namespace>
kubectl describe resourcequota -n <namespace>
kubectl get limitrange -n <namespace>
kubectl describe limitrange -n <namespace>
할당량 문제는 공유 개발 클러스터에서 일반적입니다. 팀에 충분한 물리적 클러스터 용량이 있을 수 있지만, 이전 미리보기 환경이나 정리되지 않은 완료된 작업으로 인해 네임스페이스 할당량이 소진될 수 있습니다.
현실적인 디버깅 순서
Pod가 보류 중일 때 이 순서를 사용하십시오:
kubectl describe pod를 실행하고 가장 최근 스케줄링 이벤트를 복사합니다.kubectl describe node로 요청된 CPU 및 메모리를 노드 할당 가능 용량과 비교합니다.- Pod가
nodeSelector, 노드 선호도 또는 토폴로지 키를 사용하는 경우 노드 레이블을 확인합니다. - 후보 노드의 테인트와 Pod의 톨러레이션을 확인합니다.
- Pod가 퍼시스턴트 스토리지를 마운트하는 경우 PVC 및 StorageClass를 확인합니다.
- 네임스페이스 할당량 및 LimitRanges를 확인합니다.
- Cluster Autoscaler가 도움이 될 것으로 예상되는 경우 해당 로그 또는 이벤트를 검사합니다.
이 순서가 중요한 이유는 보류 중인 Pod가 애플리케이션 런타임 문제가 아니기 때문입니다. 기본 제약 조건이 변경되지 않는 한 배포를 다시 시작해도 거의 도움이 되지 않습니다.
성공적인 스케줄링을 위한 모범 사례
스케줄링 문제를 최소화하려면 다음 운영 모범 사례를 채택하십시오:
- 리소스 요청을 명시적으로 정의: CPU 및 메모리에 대해 합리적인
requests(및 선택적limits)를 항상 설정하십시오. 이렇게 하면 스케줄러가 노드 용량을 정확하게 평가할 수 있습니다. - 영역 지정을 위해 노드 레이블 사용: 일관된 노드 레이블(예:
hardware=gpu,zone=us-east-1a)을 구현하고nodeSelector또는nodeAffinity를 사용하여 워크로드를 적절한 하드웨어로 안내하십시오. - 테인트 및 톨러레이션 문서화: 유지 관리 또는 하드웨어 분리를 위해 노드에 테인트가 있는 경우 이러한 테인트를 중앙에 문서화하십시오. 테인트된 리소스에 액세스해야 하는 애플리케이션 매니페스트에 해당 톨러레이션이 포함되어 있는지 확인하십시오.
- 클러스터 오토스케일러 모니터링(사용하는 경우): 스케일링 솔루션에 의존하는 경우 제대로 작동하는지 확인하십시오. 스케일링을 트리거해야 하는 용량 부족이 자동으로 실패하여 Pod가 보류 상태로 남을 수 있습니다.
- 스케줄러 로그 검토(고급): 심층 진단을 위해
kube-scheduler구성 요소 자체의 로그를 검토하십시오. 관리형 클러스터에서는 공급자에 따라 액세스가 다를 수 있으므로 Pod 이벤트 및 공급자별 제어 플레인 로깅부터 시작하십시오.
증상이 아닌 제약 조건을 수정하십시오
올바른 수정은 제약 조건이 우연인지 의도적인지에 따라 다릅니다. 누군가 프로덕션 매니페스트를 작은 스테이징 클러스터에 복사했기 때문에 Pod가 8개의 CPU를 요청하는 경우 해당 환경에 대한 요청을 줄이십시오. Pod에 GPU가 필요하고 GPU 노드가 없는 경우 톨러레이션을 추가해도 도움이 되지 않습니다. 클러스터에 올바른 하드웨어가 필요합니다. 테인트가 데이터베이스 노드를 일반 워크로드로부터 보호하는 경우 관련 없는 Pod를 스케줄링하기 위해 테인트를 제거하지 마십시오.
프로덕션 변경의 경우 Git에서 이유를 확인할 수 있도록 하십시오. 노드 레이블, 테인트, 선호도 규칙 및 리소스 요청은 배치 계약입니다. 미래의 운영자는 규칙이 성능, 규정 준수, 하드웨어 액세스, 비용 제어 또는 단순한 역사적 사고로 인해 존재하는지 알아야 합니다.
오해의 소지가 있는 빠른 수정 예시
몇 가지 일반적인 수정은 즉각적인 Pending 상태를 사라지게 하지만 나중에 더 심각한 문제를 만듭니다.
CPU 요청을 낮추는 것은 원래 요청이 부풀려진 경우 도움이 될 수 있지만 무료 용량 도구는 아닙니다. 애플리케이션이 피크 트래픽 중에 실제로 해당 CPU를 필요로 하는 경우 Pod가 스케줄링된 다음 부하가 심할 때 성능이 저하될 수 있습니다. 요청을 공격적으로 줄이기 전에 사용 기록과 대기 시간을 확인하십시오.
광범위한 톨러레이션을 추가하면 Pod가 스케줄링될 수 있지만 다른 목적으로 예약된 노드에 배치될 수 있습니다. 톨러레이션은 "이 Pod가 여기에 허용됩니다"라고 말합니다. "이 Pod가 여기를 선호해야 합니다"라고 말하지는 않습니다. 권한과 의도가 모두 필요한 경우 톨러레이션을 노드 선호도 또는 노드 셀렉터와 결합하십시오.
반선호도 규칙을 제거하면 복제본을 빠르게 복원할 수 있지만 모든 복제본을 하나의 노드 또는 하나의 영역에 배치할 수 있습니다. 이는 중단 중에는 때때로 허용되지만, 조용하고 영구적인 표류가 아닌 의식적인 임시 변경이어야 합니다.
클러스터를 확장하는 것이 종종 올바른 답이지만, 보류 중인 Pod가 새 노드를 사용할 수 있다는 것을 안 후에만 가능합니다. Pod에 오토스케일링된 노드 그룹이 가지지 않을 레이블이 필요한 경우 노드를 추가해도 더 많은 부적합한 노드만 제공됩니다.
최종 확인
보류 중인 Pod는 Pod와 클러스터 간의 협상 실패입니다. Pod는 특정 노드에 배치하기 위해 리소스, 레이블, 스토리지, 토폴로지 및 권한을 요청합니다. 클러스터는 용량, 테인트, 레이블, 할당량 및 사용 가능한 볼륨으로 응답합니다. kubectl describe pod는 협상이 실패한 위치를 보여줍니다. 이벤트를 주의 깊게 읽으면 대부분의 수정은 간단해집니다: Pod의 요구 사항을 변경하거나, 클러스터의 사용 가능한 용량을 변경하거나, 더 이상 현실과 일치하지 않는 정책을 수정하십시오.