Karpenter 문제 해결
Karpenter 컨트롤러, KCNodeClass, NodePool 및 NodeClaim의 상태와 이벤트를 확인하여 노드가 생성되거나 삭제되지 않는 원인을 진단합니다.
기본 진단
다음 명령으로 주요 리소스와 Warning 이벤트를 확인합니다.
kubectl -n karpenter-kakaocloud get deployment,pod
kubectl get kcnodeclass,nodepool,nodeclaim
kubectl get events -A --field-selector type=Warning \
--sort-by=.lastTimestamp
컨트롤러 로그와 문제가 발생한 리소스의 상세 정보를 확인합니다.
kubectl -n karpenter-kakaocloud logs \
deployment/karpenter-provider-kakaocloud --tail=200
kubectl describe kcnodeclass <KCNODECLASS_NAME>
kubectl describe nodepool <NODEPOOL_NAME>
kubectl describe nodeclaim <NODECLAIM_NAME>
Kubernetes 버전 차이에 대한 일부 이벤트는 Normal 유형으로 기록되어 Warning 이벤트 조회 결과에는 표시되지 않을 수 있습니다. 관련 상태는 KCNodeClass의 조건에서 확인합니다.
증상별 확인 사항
컨트롤러가 실행되지 않는 경우
- 파드가
Pending또는ContainerCreating상태인 경우: 파드 이벤트와 이미지 레지스트리 접근을 확인합니다. 자격 증명 Secret에는applicationCredentialId,applicationCredentialSecret,region, 서명 키 Secret에는keyring.json이 있어야 합니다. - 파드가
CrashLoopBackOff상태인 경우: 로그와 설치 값의region,clusterName,projectID, IAM 권한을 확인합니다.region은kr-central-2이며 서명 키는 32바이트여야 합니다. RESTARTS가 증가하지만 명확한 오류가 없는 경우: 필수 CRD의 설치 여부를 확인하고, 누락되었다면 설치한 차트 버전의 CRD를 다시 적용합니다.
노드가 생성되지 않거나 준비되지 않는 경우
- KCNodeClass의
Ready=False:status.conditions의 reason과 메시지를 확인합니다. 서브넷, 워커 보안 그룹, 워커 이미지, 키 페어 및 IAM 조회 권한을 점검합니다. KubernetesVersionReady=False: reason이UnsupportedKubernetesVersion또는KubernetesVersionSkew인지 확인합니다. Kubernetes Engine에서 제공하는 버전 중 컨트롤 플레인과 같거나 한 단계 낮은 마이너 버전을 지정합니다.KubernetesVersionDeprecated=True:WorkerVersionNotOffered는 현재 워커 버전의 신규 제공이 종료되었음을 뜻합니다. 기존 구성의 노드 생성은 계속되므로 지원 종료된 버전 안내에 따라 업데이트 일정을 수립합니다.ImagesReady=True, reasonImagesRetained: 현재 버전의 이미지를 조회하지 못해 이전 이미지를 유지하는 상태입니다. 지원 버전으로 변경하거나 검증된 이미지 ID를spec.imageID에 지정합니다.- 파드는
Pending이지만 NodeClaim이 없는 경우: NodePool과 KCNodeClass의Ready,requirements,limits, 파드 이벤트를 확인합니다. 충돌하는 인스턴스·가용 영역 조건을 완화하고 리소스 상한을 조정합니다. - NodeClaim은 있지만 노드가
Ready가 되지 않는 경우: NodeClaim 이벤트, API 서버·DNS·메타데이터 서비스 통신, NAT와 egress, 워커 보안 그룹 및 CNI 규칙을 확인합니다. 메타데이터 서비스 주소는169.254.169.254입니다. - Cilium 노드의 파드가 계속
Pending상태인 경우: Cilium DaemonSet 상태와node.cilium.io/agent-not-readystartup taint를 확인합니다. Calico 클러스터에는 이 taint를 사용하지 않습니다. - GPU 노드는
Ready지만 GPU가 0인 경우: GPU Operator와 device plugin,nvidia.com/gpu의 capacity·allocatable을 확인합니다. 자세한 내용은 GPU 런타임 확인을 참고하시기 바랍니다. - 예상하지 않은 노드 교체가 발생한 경우: NodeClaim 이벤트에서 통합·드리프트·만료 사유를 확인합니다.
consolidateAfter, 중단 예산,expireAfter, KCNodeClass 변경 이력을 점검합니다.
KCNodeClass가 Ready=False라면 각 조건의 reason과 메시지를 확인합니다.
kubectl get kcnodeclass <KCNODECLASS_NAME> \
-o jsonpath='{range .status.conditions[*]}{.type}{"\t"}{.status}{"\t"}{.reason}{"\t"}{.message}{"\n"}{end}'
주요 조건은 다음과 같습니다.
| 조건 | 확인 대상 |
|---|---|
KubernetesVersionReady | 클러스터 상태와 bootstrap.kubernetesVersion |
KubernetesVersionDeprecated | 사용 중인 워커 Kubernetes 버전의 제공 여부 |
ImagesReady | Kubernetes 버전에 맞는 워커 이미지 |
SubnetsReady | 서브넷 ID, 프로젝트 및 지원 가용 영역 |
SecurityGroupsReady | 보안 그룹 ID와 Kubernetes Engine 워커 보안 그룹 포함 여부 |
KeyPairReady | keyName에 지정한 키 페어 |
Ready | 위 조건의 종합 결과 |
업데이트 또는 삭제 중 문제가 발생한 경우
- 컨트롤 플레인 업데이트 API가 HTTP 400을 반환하는 경우: 코드가
InvalidRequest.BadRequest이고 메시지가upgrade the karpenter nodes of cluster로 시작한다면, 모든 Karpenter 노드를 현재 컨트롤 플레인 버전으로 교체한 뒤 다시 요청합니다. - 컨트롤 플레인 업데이트 API가 HTTP 500을 반환하는 경우: 코드가
InternalError.InternalServerError라면 응답만으로 버전 불일치를 판단하지 않습니다. 잠시 후 다시 요청하고, 반복되면 헬프데스크로 문의합니다. - Kubernetes Engine 노드 삭제 API가 HTTP 404를 반환하는 경우: 코드가
ResourceNotAssociated.NotFound인지 확인합니다. Karpenter 노드는 Kubernetes Engine 노드 삭제 API가 아닌 NodeClaim을 삭제하여 회수합니다. - 노드 또는 NodeClaim이 삭제되지 않는 경우: PodDisruptionBudget,
karpenter.sh/do-not-disrupt, 종료 중인 파드와 NodeClaim 이벤트를 확인합니다. 워크로드를 안전하게 중단할 수 있을 때 회수 정책을 조정하고 컨트롤러는 유지합니다. - 노드는 사라졌지만 인스턴스가 남은 경우: 콘솔의 인스턴스·볼륨과 서명 검증 로그를 확인합니다. 기존 서명 키로 컨트롤러 복구를 시도하고, 불가능하면 잔여 리소스 식별을 참고하시기 바랍니다.
- 클러스터가
Deleting상태에 머무르는 경우: 삭제 전에 기록한 인스턴스·볼륨을 콘솔과 대조합니다. 잔여 리소스 식별 후에도 상태가 계속되면 헬프데스크로 문의합니다.
GPU 런타임 확인
GPU 노드에 nvidia.com/gpu 리소스가 등록되었는지 확인합니다.
kubectl get nodes -l karpenter.sh/nodepool=karpenter-gpu \
-o custom-columns='NODE:.metadata.name,CAPACITY:.status.capacity.nvidia\.com/gpu,ALLOCATABLE:.status.allocatable.nvidia\.com/gpu'
GPU Operator의 파드가 모두 Running인데 값이 비어 있으면 containerd의 실제 적용 설정을 확인합니다. 다음 명령은 Pod Security 정책에 따라 제한될 수 있습니다.
kubectl debug node/<GPU_NODE_NAME> -it --image=busybox:1.36 -- \
chroot /host sh -c \
"containerd config dump | grep -E 'runtimes.nvidia'"
runtimes.nvidia 항목이 없으면 NVIDIA Container Toolkit 적용 상태를 확인합니다. /etc/containerd/config.toml 파일을 직접 수정하지 말고 GPU Operator가 런타임 구성을 다시 적용하도록 조치합니다.
삭제 지연 및 잔여 리소스 처리
NodeClaim 삭제가 지연되면 연결된 노드의 파드와 중단 정책을 확인합니다.
kubectl get pods -A --field-selector spec.nodeName=<NODE_NAME>
kubectl get pdb -A
kubectl describe nodeclaim <NODECLAIM_NAME>
finalizer를 강제로 제거하면 Karpenter가 인스턴스와 볼륨을 정리하지 못할 수 있습니다. 일반적인 복구 절차로 finalizer를 삭제하지 말고, 기존 서명 키와 설정으로 컨트롤러를 복구하여 삭제를 다시 시도합니다.
노드 또는 Virtual Machine의 이름이나 설명이 변경되면 자동 회수 대상에서 제외될 수 있습니다. 이 경우 NodeClaim이 삭제된 후에도 인스턴스와 요금이 남을 수 있습니다.
잔여 리소스 식별
클러스터 삭제가 완료된 뒤에도 인스턴스나 볼륨이 남아 있다면 다음 정보를 대조합니다.
- 삭제 전에 기록한 NodeClaim의 provider ID와 인스턴스·볼륨 ID
- 인스턴스 이름
karpenter-<클러스터 UID 앞 8자>-<NodeClaim 이름> v=1;m=karpenter;로 시작하는 인스턴스 설명
클러스터 UID는 kubeconfig의 API 서버 엔드포인트에 포함된 값으로, 콘솔의 클러스터 ID와 다릅니다.
해당 클러스터에서 생성한 인스턴스임이 확인되고 같은 프로젝트에 다른 Karpenter 클러스터가 없다면, Virtual Machine > 인스턴스에서 남은 인스턴스를 삭제할 수 있습니다.
볼륨은 삭제 전에 기록한 ID와 생성 일시를 대조합니다. 연결된 인스턴스가 없는 경우에만 삭제합니다. 다른 클러스터의 리소스와 구분하기 어렵다면 직접 삭제하지 말고 헬프데스크 > 기술 문의로 문의하시기 바랍니다.
CRD 및 서명 키 정리
서명 키는 남은 인스턴스의 소유권 확인에 필요합니다. 인스턴스가 모두 삭제된 것을 확인하기 전에는 서명 키 Secret과 백업을 삭제하지 않습니다.
Karpenter를 다시 설치할 계획이 없고 다른 구성이 같은 CRD를 사용하지 않는다면, Helm 릴리스 삭제 후 CRD를 삭제할 수 있습니다.
kubectl delete crd \
kcnodeclasses.karpenter.kakaocloud.com \
nodeclaims.karpenter.sh \
nodepools.karpenter.sh \
nodeoverlays.karpenter.sh \
capacitybuffers.autoscaling.x-k8s.io
남은 인스턴스가 없는 것을 확인한 뒤 보관 중인 keyring.json 백업을 정리합니다.
컨트롤러 복구가 어렵거나 인스턴스 회수 여부를 확인할 수 없으면 헬프데스크 > 기술 문의로 문의하시기 바랍니다. 문의할 때 다음 정보를 함께 전달합니다.
- 클러스터 이름과 ID
- Karpenter Provider 차트 버전과 컨트롤러 이미지
- KCNodeClass, NodePool 및 NodeClaim의 YAML
- Warning 이벤트와 컨트롤러 로그
- 관련 노드 이름과 Virtual Machine 인스턴스 ID
- 문제 발생 시각과 수행한 변경 사항