- Published on
EKS Karpenter NodeClaim NotReady 10분 진단
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버리스처럼 노드를 늘리려고 Karpenter를 붙였는데, 정작 NodeClaim이 NotReady에서 멈추면 체감 난이도가 급상승합니다. 이유는 단순히 “노드가 안 붙음”이 아니라, (1) Karpenter CRD·컨트롤러 계층, (2) EC2 인스턴스 부팅(AMI/유저데이터) 계층, (3) IAM(노드 역할/IRSA) 계층, (4) CNI(aws-node/IP 할당) 계층 중 어디서 끊겼는지에 따라 증상이 비슷하게 보이기 때문입니다.
이 글은 NodeClaim NotReady를 10분 안에 “어느 계층 문제인지” 먼저 갈라내고, 재현 가능한 명령으로 원인을 좁히는 실전 진단 루틴을 제공합니다.
> 참고로 노드가 조인했는데 kubelet NotReady로 떨어지는 케이스는 CNI 초기화 문제인 경우가 많습니다. 아래 글도 함께 보시면 진단 속도가 빨라집니다: EKS kubelet NotReady - CNI plugin not initialized 해결
0) 10분 타이머: 먼저 “어디까지 진행됐는지” 확인
NodeClaim NotReady는 크게 두 부류로 나뉩니다.
- EC2 자체가 안 뜸: Karpenter가 인스턴스를 만들지 못했거나(권한/리소스/서브넷/SG), 만들었는데 부팅 실패.
- EC2는 떴는데 클러스터 조인 실패: 부트스트랩/인증(aws-auth)/CNI/IP 부족/보안그룹/엔드포인트 문제.
가장 먼저 Karpenter 이벤트를 봅니다.
kubectl get nodeclaim -A
kubectl describe nodeclaim <nodeclaim-name>
# Karpenter 컨트롤러 로그
kubectl -n karpenter logs deploy/karpenter -c controller --tail=200
describe의 Events에 아래 단서가 자주 나옵니다.
Failed to launch/UnauthorizedOperation→ IAM/권한no subnets found/no security groups found→ 서브넷/SG 셀렉터 태그UnhealthyDependents→ 인스턴스 프로파일/인스턴스 역할 연결 문제Launched instance는 있는데 노드가 안 생김 → 부트스트랩/조인/CNI
1) CRD·컨트롤러 레벨: “Karpenter가 정상 동작 중인가?”
1-1. CRD 설치 여부와 버전 불일치
업그레이드/재설치 이후 CRD가 누락되거나 버전이 꼬이면, 컨트롤러는 떠 있는데 리소스 reconcile이 제대로 안 되는 경우가 있습니다.
kubectl get crd | grep -E 'karpenter|nodeclaim|nodepool'
# Karpenter가 사용하는 주요 리소스 확인
kubectl api-resources | grep -i karpenter
증상 힌트
no matches for kind "NodeClaim"같은 에러 → CRD 미설치- 컨트롤러 로그에
failed to list/conversion webhook에러 → CRD/웹훅/버전 문제
1-2. 컨트롤러가 AWS API 호출을 못하는지(IRSA)
Karpenter 컨트롤러는 EC2/SSM/Pricing/EKS 등 AWS API를 호출합니다. IRSA가 틀리면 AssumeRoleWithWebIdentity 단계에서 막힙니다.
kubectl -n karpenter get sa karpenter -o yaml | sed -n '1,120p'
kubectl -n karpenter describe pod -l app.kubernetes.io/name=karpenter | sed -n '1,200p'
컨트롤러 로그에서 다음이 보이면 IRSA/IAM 문제입니다.
AccessDeniedInvalidIdentityTokenNoCredentialProviders
2) IAM 레벨: NodeRole/InstanceProfile/권한 3종 세트
NodeClaim이 NotReady일 때 가장 흔한 축은 노드 인스턴스 역할(NodeRole) 이거나, 인스턴스 프로파일 연결이거나, aws-auth 매핑입니다.
2-1. EC2가 떴는지부터 확인(없으면 IAM/셀렉터/쿼터)
# NodeClaim에 찍힌 instance-id를 찾거나
kubectl get nodeclaim <name> -o jsonpath='{.status.providerID}{"\n"}'
# 또는 Karpenter 로그에서 instance-id 확인 후
aws ec2 describe-instances --instance-ids i-xxxxxxxxxxxxxxxxx \
--query 'Reservations[0].Instances[0].{State:State.Name,Subnet:SubnetId,SG:SecurityGroups[*].GroupId,Profile:IamInstanceProfile.Arn,AZ:Placement.AvailabilityZone}'
- 인스턴스가 아예 없다 → Karpenter 컨트롤러 IAM 또는 서브넷/SG 선택자/쿼터
- 인스턴스는 running → 다음 단계(조인 실패)로 이동
2-2. NodeRole에 꼭 필요한 권한(최소 체크)
EKS 노드가 조인하려면 일반적으로 다음 AWS managed policy 조합이 필요합니다(조직 정책에 따라 커스텀 가능).
AmazonEKSWorkerNodePolicyAmazonEKS_CNI_Policy(또는 CNI가 IRSA면 노드 역할에서 제거 가능)AmazonEC2ContainerRegistryReadOnly
추가로 Karpenter 환경에서는 SSM, EBS CSI, CloudWatch Agent 등을 쓰면 더 필요합니다.
# 인스턴스 프로파일에 연결된 role 이름 확인
aws iam get-instance-profile --instance-profile-name <profile-name>
# role에 붙은 정책 확인
aws iam list-attached-role-policies --role-name <node-role-name>
2-3. aws-auth 매핑 누락(노드 인증 실패)
노드가 부팅은 됐는데 클러스터에 Node 오브젝트가 생기지 않거나, 생겼다가 NotReady로 남는다면 aws-auth 누락을 의심합니다.
kubectl -n kube-system get cm aws-auth -o yaml
mapRoles에 NodeRole이 매핑되어야 합니다(예시).
mapRoles: |
- rolearn: arn:aws:iam::<ACCOUNT_ID>:role/<NodeRoleName>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
> 운영 환경에서는 GitOps/관리형 애드온/terraform으로 aws-auth를 일관되게 관리하세요. 수동 수정은 드리프트를 만들기 쉽습니다.
3) AMI·부트스트랩 레벨: “노드가 EKS에 조인하는가?”
EC2는 떴는데 Node가 안 보이면, 대부분 부트스트랩(userData) 또는 AMI/EKS 버전 불일치에서 터집니다.
3-1. 인스턴스 시스템 로그로 부트스트랩 실패 확인
aws ec2 get-console-output --instance-id i-xxxxxxxxxxxxxxxxx --latest \
--query 'Output' --output text | tail -n 80
다음 키워드를 찾습니다.
bootstrap.sh실패kubelet인증서/토큰 관련 에러cannot reach/timeout(EKS API 엔드포인트 접근 문제)
3-2. 프라이빗 클러스터에서 API 엔드포인트 라우팅
프라이빗 엔드포인트만 열어둔 EKS에서, Karpenter가 띄운 노드가 컨트롤 플레인에 접근할 네트워크 경로가 없으면 조인에 실패합니다.
- 노드 서브넷의 라우트 테이블
- VPC 엔드포인트(EKS, STS 등) 또는 NAT
- 보안그룹 egress
특히 STS 접근이 막히면 토큰/인증에서 다양한 형태로 실패합니다. 네트워크/엔드포인트 진단 감각은 아래 글이 도움이 됩니다: EKS Pod→S3 504 타임아웃 - VPC 엔드포인트·NAT·DNS 진단
4) CNI 레벨: Node는 생겼는데 NotReady(또는 Pod가 안 뜸)
kubectl get nodes에 노드가 보이는데 NotReady라면, 우선 노드 컨디션과 kubelet 메시지를 봅니다.
kubectl get nodes
kubectl describe node <node-name> | sed -n '1,220p'
여기서 대표적으로 많이 보는 문구가:
network plugin is not ready: cni plugin not initializedContainer runtime network not ready
이면 CNI 초기화 실패입니다. 아래 순서로 확인합니다.
4-1. aws-node(DaemonSet) 상태
kubectl -n kube-system get ds aws-node
kubectl -n kube-system get pods -l k8s-app=aws-node -o wide
kubectl -n kube-system logs -l k8s-app=aws-node --tail=200
aws-node가 새 노드에 스케줄되지 않거나 CrashLoop이면, 노드는 Ready로 못 올라옵니다.
4-2. IP 부족(서브넷 IP 고갈 / prefix delegation)
Karpenter로 스케일 아웃하면 서브넷 IP가 먼저 바닥나는 경우가 흔합니다. 이때 노드는 떠도 Pod IP 할당이 막혀 Ready가 늦어지거나, 워크로드가 Pending에 걸립니다.
aws ec2 describe-subnets --subnet-ids subnet-xxxx subnet-yyyy \
--query 'Subnets[*].{SubnetId:SubnetId,AZ:AvailabilityZone,AvailableIp:AvailableIpAddressCount,CIDR:CidrBlock}'
AvailableIpAddressCount가 낮으면: 더 큰 CIDR, 서브넷 추가, 또는 CNI prefix delegation 검토
4-3. CNI 권한(aws-node IRSA 사용 시)
최근 구성에서는 aws-node가 IRSA로 ENI/IP를 관리하기도 합니다. 이때 IRSA가 깨지면 노드 네트워킹이 올라오지 않습니다.
aws-node서비스어카운트 annotation- OIDC provider/Trust policy
- 필요한 EC2 권한
관련 진단 흐름은 ContainerCreating에서 멈출 때 체크리스트와도 동일한 축이 많습니다: EKS Pod가 ContainerCreating에 멈출 때 10분 진단
5) 실전 “10분 체크리스트” (복붙용)
아래를 위에서 아래로 실행하면, 보통 10분 내에 범위를 확 줄일 수 있습니다.
# 1) Karpenter/NodeClaim 이벤트
kubectl get nodeclaim
kubectl describe nodeclaim <nodeclaim>
# 2) Karpenter 컨트롤러 로그
kubectl -n karpenter logs deploy/karpenter -c controller --tail=200
# 3) EC2 생성 여부
INSTANCE_ID=$(kubectl get nodeclaim <nodeclaim> -o jsonpath='{.status.providerID}' | sed 's|.*/||')
echo "$INSTANCE_ID"
aws ec2 describe-instances --instance-ids "$INSTANCE_ID" \
--query 'Reservations[0].Instances[0].{State:State.Name,Subnet:SubnetId,Profile:IamInstanceProfile.Arn,SG:SecurityGroups[*].GroupId,AZ:Placement.AvailabilityZone}'
# 4) aws-auth 매핑
kubectl -n kube-system get cm aws-auth -o yaml
# 5) 노드가 보이면 CNI 확인
kubectl get nodes -o wide
kubectl -n kube-system get pods -l k8s-app=aws-node -o wide
kubectl -n kube-system logs -l k8s-app=aws-node --tail=200
# 6) 서브넷 IP 여유
aws ec2 describe-subnets --subnet-ids <subnet-1> <subnet-2> \
--query 'Subnets[*].{SubnetId:SubnetId,AvailableIp:AvailableIpAddressCount,AZ:AvailabilityZone}'
6) 케이스별 빠른 결론(원인 → 조치)
케이스 A: UnauthorizedOperation / AccessDenied로 인스턴스 생성 실패
- 원인: Karpenter 컨트롤러 IRSA 정책 부족(EC2 RunInstances, iam:PassRole 등)
- 조치: Karpenter 공식 권한 세트 재점검, 특히
iam:PassRole대상이 NodeRole로 제한되어 있는지 확인
케이스 B: 인스턴스는 running인데 Node가 클러스터에 안 나타남
- 원인:
aws-auth에 NodeRole 미매핑, 부트스트랩 실패, API 엔드포인트 경로 부재 - 조치: aws-auth 수정(또는 IaC로 반영), console output에서 bootstrap/kubelet 에러 확인, 프라이빗 클러스터면 NAT/VPC 엔드포인트/SG egress 점검
케이스 C: Node는 생겼는데 NotReady + cni plugin not initialized
- 원인: aws-node 미기동/CrashLoop, CNI 권한(IRSA) 문제, 서브넷 IP 고갈
- 조치: aws-node 로그 확인, IRSA/정책 수정, 서브넷 확장 또는 CNI 튜닝(prefix delegation)
7) 재발 방지: 관측 포인트 3가지
- Karpenter 컨트롤러 경보:
AccessDenied,Failed to launch,no subnets found를 로그 기반 메트릭으로 알람화 - 서브넷 IP 수명 관리: 스케일 아웃 이벤트 대비
AvailableIpAddressCount모니터링 - CNI/노드 부트스트랩 표준화: EKS 버전별 AMI/부트스트랩을 IaC로 고정하고, 변경 시 롤링 전략 마련
마무리
NodeClaim NotReady는 “Karpenter가 문제”라기보다, CRD/컨트롤러 → EC2 생성 → 노드 인증(IAM/aws-auth) → CNI 네트워크로 이어지는 체인 중 어디가 끊겼는지를 빨리 가르는 게임입니다. 위 체크리스트대로 보면 대부분은 1) 권한(특히 PassRole·aws-auth), 2) 프라이빗 네트워크에서의 API/STS 경로, 3) CNI/IP 고갈 중 하나로 수렴합니다.
다음 단계로, 노드가 Ready인데도 워크로드가 Pending에 걸린다면 스케줄링 조건/리소스/taint까지 확장해서 보셔야 합니다: EKS Pod Pending 0/XX nodes available 원인별 해결