Published on

EKS Node NotReady - CNI ENI 할당 실패 해결 가이드

Authors

서론

EKS에서 신규 노드가 조인되거나(Scale-out), 기존 노드가 재부팅/교체된 직후 갑자기 Node NotReady로 떨어지는 케이스 중 상당수는 Amazon VPC CNI(aws-node)ENI(Elastic Network Interface) 또는 Pod IP 할당을 끝내지 못해 kubelet 네트워크 준비가 완료되지 않는 상황에서 발생합니다. 이때 워커 노드 자체는 EC2 레벨에서 “running”이고 SSH도 되는데, Kubernetes에서는 NotReady로 남아 스케줄링이 막히고, 이미 떠 있던 Pod가 재시작/재배치되며 장애가 커집니다.

이 글에서는 “CNI가 ENI를 못 붙인다”는 증상을 로그/이벤트로 확증하고, 원인을 서브넷 IP 고갈, 인스턴스 ENI/IP 한도, IAM 권한, 보안그룹/네트워크 경로, IMDS/메타데이터 접근 관점에서 빠르게 좁혀 실제 복구까지 이어지는 절차를 제공합니다.


1) 증상 패턴: 무엇이 보이나?

1.1 Node 상태와 이벤트

kubectl get nodes -o wide
kubectl describe node <node-name>

describe에서 흔히 보이는 단서:

  • ReadyFalse
  • KubeletNotReady
  • 메시지에 network plugin is not ready: cni config uninitialized 또는 유사 문구

1.2 aws-node(CNI) Pod 상태와 로그

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

ENI/IP 할당 실패 시 자주 나오는 로그 키워드(예시):

  • failed to assign an IP address to container
  • failed to allocate ENI
  • AssignPrivateIpAddresses / CreateNetworkInterface API 에러
  • UnauthorizedOperation / AccessDenied
  • InsufficientFreeAddressesInSubnet
  • NetworkInterfaceLimitExceeded
  • RequestError: send request failed (메타데이터/네트워크 경로 문제)

> 참고: Pod가 Pending으로만 남는 “IP 부족”과 달리, 여기서는 노드 자체가 Ready로 못 올라오는 경우가 많습니다. 다만 근본 원인이 IP 고갈인 경우도 흔합니다. 관련해서는 Kubernetes CNI IP 부족으로 Pod Pending 해결 가이드 도 함께 보면 원인 분리가 빨라집니다.


2) 원인 맵: ENI 할당 실패가 생기는 대표 케이스

ENI 할당 실패는 결국 EC2/VPC 리소스 할당이 막히거나, CNI가 그 API를 호출할 수 없거나, 호출 결과를 반영할 수 없는 상태로 요약됩니다.

2.1 서브넷 Free IP 부족(가장 흔함)

EKS VPC CNI는 노드에 ENI를 붙이고, ENI에 여러 개의 secondary private IP를 붙여 Pod IP로 사용합니다. 따라서 노드가 속한 서브넷에 남은 IP가 부족하면 ENI 생성/secondary IP 추가가 실패합니다.

증상:

  • aws-node 로그에 InsufficientFreeAddressesInSubnet
  • 특정 AZ/서브넷에서만 NotReady가 반복

2.2 인스턴스 타입 ENI/IP 한도 초과

각 인스턴스 타입은 붙일 수 있는 ENI 수와 ENI당 IP 수가 제한됩니다. 노드에 이미 ENI가 꽉 찼거나, CNI 설정(WARM_IP_TARGET 등) 때문에 미리 확보하려다 한도를 초과하면 실패합니다.

증상:

  • NetworkInterfaceLimitExceeded
  • PrivateIpAddressLimitExceeded

2.3 노드 IAM(Role) 권한 부족

CNI는 EC2 API를 호출합니다. 노드 인스턴스 프로파일(또는 IRSA 사용 시 aws-node의 역할)이 ec2:CreateNetworkInterface, ec2:AssignPrivateIpAddresses 등을 못 하면 ENI/IP 할당이 실패합니다.

증상:

  • AccessDenied / UnauthorizedOperation
  • 특정 노드그룹만 문제(역할 차이)

2.4 보안그룹/네트워크 경로 문제(EC2 API/STS/IMDS)

CNI는 메타데이터(IMDS)로 자신의 인스턴스 정보/자격증명을 얻고, EC2 API/STS로 호출합니다. 다음이 깨지면 할당 실패로 이어집니다.

  • IMDS 접근 차단(iptables, hop limit, IMDSv2 강제 설정 불일치)
  • VPC 엔드포인트/프록시/방화벽으로 EC2 API 호출 실패
  • CoreDNS/노드 DNS 문제로 AWS API 도메인 해석 실패

이 경우 aws-node 로그에 타임아웃/연결 실패가 섞여 나옵니다. 클러스터 전반의 API 통신 문제와도 연관될 수 있어, 필요하면 Kubernetes apiserver i/o timeout 원인과 해결 도 같이 점검하세요.


3) 15분 내 트리아지(원인 좁히기 체크리스트)

아래 순서대로 하면 “IP냐, 한도냐, 권한이냐, 네트워크냐”가 빠르게 갈립니다.

3.1 aws-node 로그에서 에러 코드 먼저 잡기

kubectl -n kube-system logs -l k8s-app=aws-node --since=30m | egrep -i "error|fail|denied|limit|insufficient|timeout" | tail -n 80
  • InsufficientFreeAddressesInSubnet → 3.2로
  • LimitExceeded 계열 → 3.3으로
  • AccessDenied/Unauthorized → 3.4로
  • timeout, no such host, connection refused → 3.5로

3.2 서브넷 IP 잔량 확인

AWS CLI(운영 계정에서):

aws ec2 describe-subnets \
  --subnet-ids subnet-aaa subnet-bbb \
  --query 'Subnets[].{SubnetId:SubnetId,AZ:AvailabilityZone,CIDR:CidrBlock,Available:AvailableIpAddressCount}' \
  --output table

AvailableIpAddressCount가 낮으면(특히 수십 이하) 노드 스케일아웃/Pod 증가 시 바로 터집니다.

3.3 인스턴스 ENI/IP 한도 확인

노드 인스턴스 타입과 현재 붙은 ENI 확인:

# 노드가 어떤 인스턴스인지
kubectl get node <node-name> -o jsonpath='{.metadata.labels.node\.kubernetes\.io/instance-type}'; echo

# EC2에서 현재 네트워크 인터페이스 수
aws ec2 describe-instances --instance-ids i-xxxx \
  --query 'Reservations[0].Instances[0].NetworkInterfaces[].NetworkInterfaceId' --output text

한도는 AWS 문서/Service Quotas 기준이지만, 실무적으로는 “노드에 붙은 ENI가 이미 max 근처”거나 “CNI가 미리 IP를 과하게 확보”하는 설정이면 문제가 됩니다.

3.4 IAM 권한 확인(노드 Role / aws-node Role)

노드그룹이 사용하는 인스턴스 프로파일(Role) 확인 후, AmazonEKS_CNI_Policy 또는 동등 권한이 있는지 봅니다.

aws iam list-attached-role-policies --role-name <NodeInstanceRoleName>

IRSA로 aws-node에 별도 Role을 줬다면, kube-system의 serviceAccount와 연결된 roleArn 및 정책을 확인하세요.

3.5 IMDS/네트워크 경로 확인(노드 내부)

노드에 접속 가능하다면 IMDSv2 토큰/메타데이터 조회가 되는지부터 확인합니다.

TOKEN=$(curl -sS -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/instance-id

여기서 막히면 CNI가 자격증명/인스턴스 정보를 못 얻어 ENI 작업이 실패할 수 있습니다.

또한 노드에서 AWS API 도메인이 해석/접속되는지도 확인합니다(프라이빗 클러스터라면 VPC 엔드포인트 구성 포함).

# DNS
nslookup ec2.${AWS_REGION}.amazonaws.com

# HTTPS 연결
curl -sS https://ec2.${AWS_REGION}.amazonaws.com/ -o /dev/null -w "%{http_code}\n"

4) 해결책: 원인별로 “바로 적용 가능한” 복구 방법

4.1 서브넷 IP 부족 해결

(1) 가장 안전: 서브넷 확장/추가

  • 더 큰 CIDR로 새 서브넷을 추가하고 노드그룹을 그 서브넷까지 사용하도록 확장
  • 또는 VPC에 secondary CIDR를 붙이고 새 서브넷 구성

운영 팁:

  • 특정 AZ만 IP가 고갈되면, 그 AZ 서브넷만 증설해도 효과가 큼
  • 노드그룹이 사용하는 서브넷 리스트를 확인하고, “문제 서브넷만” 포함되어 있지 않은지 점검

(2) 임시 완화: Pod 밀도 낮추기

  • 노드 수를 늘리기 전에(역설적이지만) Pod 분산이 먼저 필요할 수 있음
  • maxPods를 낮추거나, 인스턴스 타입을 ENI/IP 여유가 큰 것으로 변경

> IP 고갈은 Pod Pending으로도 나타납니다. 증상이 섞여 있다면 Kubernetes CNI IP 부족으로 Pod Pending 해결 가이드 의 “WARM_IP_TARGET/Prefix Delegation” 파트를 같이 적용하는 것이 좋습니다.

4.2 ENI/IP 한도 초과 해결

(1) CNI 사전 할당 설정(WARM_*) 조정

aws-node DaemonSet의 env를 조정해 “미리 확보하는 IP”를 줄일 수 있습니다.

kubectl -n kube-system edit ds aws-node

예시(환경에 맞게 보수적으로):

spec:
  template:
    spec:
      containers:
      - name: aws-node
        env:
        - name: WARM_IP_TARGET
          value: "2"
        - name: MINIMUM_IP_TARGET
          value: "1"
  • WARM_IP_TARGET: 노드가 여유로 들고 있을 IP 수
  • MINIMUM_IP_TARGET: 최소 확보 IP 수

과도한 warm 설정은 대규모 스케일 시 ENI/IP를 빠르게 고갈시켜 NotReady를 유발할 수 있습니다.

(2) Prefix Delegation(지원 환경에서)로 IP 효율 개선

지원되는 인스턴스/버전 조합이라면 Prefix Delegation을 켜서 ENI당 더 효율적으로 IP를 관리할 수 있습니다. (적용 전 CNI 버전/인스턴스 타입/운영 정책 검토 필수)

4.3 IAM 권한 문제 해결

(1) 노드 Role에 CNI 정책 부여

가장 흔한 정답은 노드 인스턴스 Role에 AWS 관리형 정책을 붙이는 것입니다.

aws iam attach-role-policy \
  --role-name <NodeInstanceRoleName> \
  --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

조직 정책상 최소권한이 필요하면, 해당 정책 문서에서 필요한 EC2 권한만 추려 커스텀 정책으로 구성하세요.

(2) IRSA 사용 시 aws-node SA 역할 점검

  • kube-system:aws-node serviceAccount에 eks.amazonaws.com/role-arn이 올바른지
  • 그 Role에 EC2 네트워크 관련 권한이 있는지

권한이 맞는데도 AccessDenied가 난다면 SCP/Permission Boundary/세션 정책이 막는지까지 봐야 합니다.

4.4 보안그룹/네트워크 경로 문제 해결

(1) 프라이빗 클러스터: VPC 엔드포인트 점검

노드가 NAT 없이 프라이빗 서브넷에 있고, AWS API로 나가야 한다면 최소한 다음이 필요할 수 있습니다.

  • com.amazonaws.<region>.ec2
  • com.amazonaws.<region>.sts
  • (ECR 사용 시) ecr.api, ecr.dkr, s3 게이트웨이 엔드포인트 등

엔드포인트에 연결된 SG/NACL이 443 아웃바운드/리턴 트래픽을 허용하는지 확인하세요.

(2) IMDS 설정(IMDSv2, hop limit) 정합성

  • EC2에서 IMDSv2 required로 강제했는데, 노드/에이전트가 토큰을 못 쓰는 구성이면 문제
  • 컨테이너 네트워크 경로에서 hop limit가 너무 낮아 메타데이터 접근이 끊기는 케이스도 존재

IMDS가 막히면 CNI뿐 아니라 다양한 에이전트가 연쇄적으로 실패할 수 있습니다.


5) 복구 절차(운영 관점): 안전하게 정상화하기

원인을 고친 뒤에도 이미 NotReady로 빠진 노드는 “자연 회복”이 안 되는 경우가 있습니다. 아래 순서가 안전합니다.

5.1 aws-node 롤링 재시작

kubectl -n kube-system rollout restart ds/aws-node
kubectl -n kube-system rollout status ds/aws-node --timeout=5m

5.2 문제 노드 드레인 후 교체(Managed Node Group 권장)

kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --grace-period=60

이후 노드그룹에서 인스턴스를 교체(terminate)해 새 노드가 정상 조인되는지 확인합니다.

5.3 Ready 복귀 확인

kubectl get nodes
kubectl -n kube-system get pods -l k8s-app=aws-node -o wide

노드가 Ready가 됐는데도 애플리케이션 장애가 남아 있다면, 파생 증상(예: Ingress 504, DNS, 타임아웃)을 별도로 추적해야 합니다. 예컨대 외부에서는 504가 나는데 Pod는 정상이라면 EKS ALB Ingress 504인데 Pod는 정상일 때 의 체크리스트가 도움이 됩니다.


6) 재발 방지 체크리스트(현업에서 효과 큰 것들)

6.1 서브넷 IP 모니터링과 스케일 정책 연동

  • AvailableIpAddressCount를 CloudWatch/Datadog 등으로 수집
  • 임계치(예: 20% 이하 또는 절대값 256 이하 등)에서 알람
  • Cluster Autoscaler/Karpenter 스케일과 “서브넷 여유”를 함께 고려

6.2 인스턴스 타입 선택을 Pod 밀도 기준으로

  • 단순 vCPU/메모리만 보지 말고 ENI/IP capacity를 포함해 노드 타입을 선정
  • 고밀도 워크로드는 Prefix Delegation 또는 더 큰 네트워크 용량의 인스턴스 타입 고려

6.3 CNI 버전 관리와 변경 이력

  • aws-node(CNI) 업그레이드를 정기적으로 수행
  • WARM_*/ENABLE_PREFIX_DELEGATION 같은 설정 변경은 반드시 변경 이력과 함께 롤백 플랜 준비

6.4 “NotReady”의 다른 원인과 구분

네트워크 플러그인 문제처럼 보여도 실제로는 kubelet 내부 이슈(예: PLEG)인 경우도 있습니다. aws-node 로그가 깨끗한데 NotReady가 지속된다면 EKS kubelet NotReady - PLEG is not healthy 7가지 처럼 kubelet 관점 점검으로 전환하세요.


결론

EKS에서 Node NotReady가 발생하고 aws-node가 ENI/IP 할당에 실패하는 문제는, 대부분 (1) 서브넷 IP 고갈, (2) 인스턴스 ENI/IP 한도, (3) IAM 권한, (4) IMDS/AWS API 네트워크 경로 중 하나로 수렴합니다. 핵심은 감으로 접근하지 말고 aws-node 로그의 에러 코드로 갈래를 먼저 타고, AWS CLI로 서브넷 잔량/ENI 상태/권한을 확인한 뒤, 설정 조정 또는 인프라 증설로 해결하는 것입니다.

운영에서 가장 중요한 재발 방지는 “서브넷 IP 잔량 모니터링 + CNI 사전 할당 전략 최적화 + 노드 타입의 네트워크 용량 고려” 세 가지입니다. 이를 갖추면 스케일 이벤트가 곧바로 NotReady 장애로 번지는 일을 크게 줄일 수 있습니다.