Published on

EKS에서 Pod가 노드에 안붙을 때 - PodCIDR 고갈 해결

Authors

서론

EKS에서 갑자기 Pod가 Pending으로 멈추고, 오토스케일링으로 노드를 늘려도 특정 노드에는 Pod가 “안 붙는” 현상이 반복될 때가 있습니다. 이벤트를 보면 Insufficient pods 또는 CNI 쪽 에러가 보이는데, CPU/메모리는 넉넉하고 디스크도 멀쩡합니다. 이때 흔한 원인 중 하나가 PodCIDR(정확히는 노드가 사용할 수 있는 Pod IP 풀) 고갈입니다.

EKS 기본 네트워킹(amazon-vpc-cni)은 Pod에 VPC IP를 직접 할당합니다. 즉, 노드가 사용할 수 있는 ENI/Secondary IP가 바닥나면 그 노드에는 더 이상 Pod IP를 줄 수 없고, 결과적으로 Pod가 스케줄링되지 않거나(혹은 스케줄링되더라도 CNI에서 IP 할당 실패로) 생성이 실패합니다.

이 글에서는 “Pod가 노드에 안 붙음”을 PodCIDR/IP 고갈 관점에서 빠르게 확인하고, 가장 흔한 해결책(서브넷 확장, Prefix Delegation, 인스턴스 타입 변경, CNI 설정 조정)을 정리합니다.

1) 증상: Pod는 Pending, 노드는 여유, 그런데 스케줄 불가

대표적인 증상 패턴은 다음 중 하나로 나타납니다.

  • kubectl get pods에서 특정 워크로드가 계속 Pending
  • kubectl describe pod 이벤트에 다음과 유사한 메시지
    • 0/XX nodes are available: XX Insufficient pods.
    • failed to assign an IP address to container
    • add cmd: failed to assign an IP address to container
  • 노드 리소스(CPU/Memory)는 남아 있는데 Pod가 더 안 올라감
  • 노드를 더 늘리면 일시적으로 풀리지만 곧 재발(서브넷 전체 IP가 부족한 경우)

여기서 Insufficient pods는 “Pod 개수 제한”처럼 보이지만, EKS/VPC CNI 환경에서는 실제로는 노드가 할당 가능한 Pod IP가 부족할 때도 동일하게 나타납니다.

2) 10분 진단: 어디가 고갈인가? (노드 단위 vs 서브넷 단위)

문제는 크게 두 갈래입니다.

  • (A) 노드 단위 고갈: 특정 노드에서 ENI/Secondary IP가 부족
  • (B) 서브넷 단위 고갈: 노드를 늘려도 서브넷의 남는 IP 자체가 부족

2.1 Pod 이벤트로 CNI/IP 할당 실패 확인

kubectl describe pod <pod-name> -n <ns>

이벤트에 failed to assign an IP address가 보이면 거의 확정적으로 CNI IP 할당 문제입니다.

2.2 노드에서 “pods capacity”와 실제 Pod 수 비교

kubectl get nodes -o wide
kubectl describe node <node-name> | sed -n '/Capacity:/,/Allocatable:/p'

여기서 pods: 값이 노드가 수용 가능한 Pod 최대치입니다. VPC CNI에서는 이 값이 인스턴스 타입의 ENI/IPv4 한계에 의해 결정됩니다.

2.3 aws-node(amazon-vpc-cni) 로그 확인

aws-nodekube-system 네임스페이스의 DaemonSet입니다.

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

다음 키워드가 보이면 IP 부족/할당 실패를 의심하세요.

  • IPAM 관련 에러
  • no available IP addresses
  • failed to allocate IP

2.4 (서브넷 단위) VPC 서브넷 남은 IP 확인

노드를 늘려도 바로 다시 막히면, 서브넷의 free IP가 부족할 가능성이 큽니다.

aws ec2 describe-subnets \
  --subnet-ids subnet-xxxx subnet-yyyy \
  --query 'Subnets[].{SubnetId:SubnetId,CidrBlock:CidrBlock,AvailableIpAddressCount:AvailableIpAddressCount}' \
  --output table

AvailableIpAddressCount가 낮으면(예: 수십~수백 수준) 스케일아웃 시 곧 고갈됩니다.

3) 원리 이해: “PodCIDR 고갈”이 실제로 의미하는 것

전통적인 Kubernetes(kube-controller-manager가 노드에 podCIDR를 할당하고, CNI가 그 대역에서 Pod IP를 뽑는 모델)에서는 “PodCIDR 고갈”이 정말로 노드별 CIDR 블록 고갈을 뜻합니다.

하지만 EKS의 기본 CNI(amazon-vpc-cni)는 보통 다음 구조로 이해하는 게 실전에서 더 정확합니다.

  • Pod IP는 VPC 서브넷 CIDR에서 직접 할당
  • 노드는 ENI(Elastic Network Interface)를 붙이고, 각 ENI에 Secondary IP를 여러 개 붙여 Pod에 배정
  • 따라서 고갈 지점은
    • 노드가 더 붙일 수 있는 ENI/Secondary IP 한계(인스턴스 타입 제한)
    • 서브넷 전체에서 남아있는 IPv4 부족

즉, 현상은 “PodCIDR 고갈”처럼 보이지만, 실제 해결은 VPC IP 공급량을 늘리거나(IP 확장), 노드가 IP를 더 효율적으로 쓰게 하거나(Prefix Delegation), 인스턴스 타입을 바꾸는 것입니다.

4) 해결책 1: Prefix Delegation 활성화(가장 흔한 정답)

EKS VPC CNI의 Prefix Delegation(PD) 을 켜면, 노드에 개별 Secondary IP를 여러 개 붙이는 대신 /28 프리픽스 단위로 IP를 위임받아 더 많은 Pod IP를 효율적으로 관리합니다. 대규모/고밀도 배치에서 IP 부족 문제를 크게 줄일 수 있습니다.

이 주제는 케이스가 다양하고 “PD를 켰는데도 부족”한 경우도 있어, 아래 글을 함께 참고하면 좋습니다.

4.1 CNI 환경 변수 설정(예시)

aws-node DaemonSet에 다음 설정을 적용합니다(클러스터/버전에 따라 권장값은 다를 수 있음).

kubectl -n kube-system set env daemonset/aws-node \
  ENABLE_PREFIX_DELEGATION=true \
  WARM_PREFIX_TARGET=1
  • ENABLE_PREFIX_DELEGATION=true: PD 활성화
  • WARM_PREFIX_TARGET=1: 미리 확보해둘 prefix 수(트래픽/스케일 패턴에 맞게 조정)

적용 후 롤링 업데이트를 확인합니다.

kubectl -n kube-system rollout status ds/aws-node

4.2 PD 활성화 후 검증 포인트

  • 새로 뜨는 노드부터 효과가 커지는 경우가 많습니다(기존 노드는 재시작/교체 필요할 수 있음).
  • aws-node 로그에서 prefix 관련 할당 로그가 보이는지 확인
  • 동일 인스턴스 타입에서 노드당 수용 가능한 Pod 수가 증가했는지 확인

5) 해결책 2: 서브넷 CIDR 확장 또는 신규 서브넷 추가

서브넷 자체의 AvailableIpAddressCount가 낮다면, PD를 켜도 근본적으로 IP 공급이 부족합니다. 이때는 네트워크 설계를 바꿔야 합니다.

현실적인 선택지는 다음입니다.

  • (권장) 신규 서브넷 추가: 더 큰 CIDR의 서브넷을 추가하고, 노드그룹이 해당 서브넷을 사용하도록 구성
  • VPC에 Secondary CIDR 추가 후 서브넷 확장: 기존 VPC에 보조 CIDR을 붙이고, 추가 서브넷 생성

5.1 노드그룹 서브넷 변경(예: eksctl)

# nodegroup-subnets.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: my-eks
  region: ap-northeast-2
managedNodeGroups:
  - name: ng-1
    instanceType: m6i.large
    desiredCapacity: 3
    privateNetworking: true
    subnets:
      - subnet-aaaa1111
      - subnet-bbbb2222

적용:

eksctl create nodegroup -f nodegroup-subnets.yaml

기존 노드그룹을 교체(블루/그린)하는 방식이 안전합니다.

6) 해결책 3: 인스턴스 타입 변경(ENI/IPv4 한계 상향)

노드 단위로만 막히고 서브넷 IP는 넉넉하다면, 인스턴스 타입의 ENI/IPv4 한계가 병목일 수 있습니다. 더 많은 ENI/IPv4를 지원하는 타입으로 바꾸면 노드당 Pod 수가 늘어납니다.

실전 팁:

  • “CPU/메모리 여유인데 Pod가 안 붙는” 노드는 네트워크 한계일 가능성이 큼
  • 워크로드가 작은 Pod 위주라면, 노드당 Pod 밀도가 높아져 IP 한계에 빨리 도달

검증은 kubectl describe nodeCapacity.pods 변화로 확인합니다.

7) 해결책 4: WARM_* 튜닝으로 스케일 순간 장애 줄이기

IP가 “완전히 고갈”되기 전이라도, 스케일아웃 순간에 IP를 늦게 확보해서 잠깐 Pending이 몰릴 수 있습니다. 이때 WARM_IP_TARGET, WARM_ENI_TARGET, MINIMUM_IP_TARGET 같은 설정이 영향을 줍니다.

예시(환경에 맞게 조정 필요):

kubectl -n kube-system set env daemonset/aws-node \
  WARM_IP_TARGET=10 \
  MINIMUM_IP_TARGET=20
  • WARM_IP_TARGET: 미리 확보해둘 여유 IP 개수
  • MINIMUM_IP_TARGET: 최소 유지할 IP 개수

주의: 과도하게 올리면 서브넷 IP를 더 빨리 소진할 수 있습니다. “서브넷 단위 고갈”이 의심될 때는 오히려 역효과가 날 수 있습니다.

8) 운영 관점 체크리스트(재발 방지)

8.1 모니터링 지표

  • 서브넷 AvailableIpAddressCount(CloudWatch/주기적 점검)
  • 노드당 Pod 수(파드 밀도)
  • aws-node 로그에서 IPAM 오류 빈도

8.2 배포/스케일 정책

  • HPA/KEDA로 급격히 늘어나는 워크로드는 WARM 타깃과 함께 설계
  • 작은 Pod가 많다면 인스턴스 타입/PD로 “Pod per node” 상한을 먼저 계산

8.3 함께 자주 엮이는 이슈

EKS에서 네트워크/권한 문제가 동시에 터지면 원인 분리가 어려워집니다. 예를 들어, Pod는 떴는데 AWS API 호출이 403이면 IRSA/STS 문제일 수 있습니다. 아래 글들도 같은 운영 맥락에서 자주 참고합니다.

9) 결론: “노드에 안 붙는 Pod”는 대개 IP가 먼저다

EKS에서 Pod가 노드에 안 붙을 때, CPU/메모리만 보고 있으면 시간을 많이 씁니다. 특히 이벤트에 Insufficient pods가 보이면 Pod 수 제한이 아니라 IP 풀 고갈일 가능성이 높습니다.

정리하면 우선순위는 다음이 실전에서 가장 효율적입니다.

  1. describe pod/aws-node 로그로 IP 할당 실패 여부 확인
  2. 서브넷 AvailableIpAddressCount로 “서브넷 단위 고갈”인지 판단
  3. Prefix Delegation 활성화 + WARM 타깃 적정화
  4. 필요 시 서브넷 확장/추가, 인스턴스 타입 상향, 노드그룹 교체

이 흐름대로만 점검해도 “Pod가 Pending인데 이유를 모르겠다”에서 빠르게 벗어날 수 있습니다.