Published on

Kubernetes CNI IP 부족으로 Pod Pending 해결 가이드

Authors

서버가 멀쩡해 보이는데도 새로 뜨는 Pod가 Pending에서 멈추는 상황은 운영에서 자주 만나는 장애 유형입니다. 특히 클러스터가 일정 규모를 넘거나 노드/파드 스케일링이 잦은 환경에서는 CNI의 Pod IP 할당 풀이 고갈(IP exhaustion) 되면서 스케줄러는 배치하려고 하는데 실제 네트워크가 따라주지 못해 멈추는 일이 발생합니다.

이 글에서는 “CNI IP 부족”이 실제로 어떤 이벤트/로그로 나타나는지, 어떤 지표로 빠르게 확정 진단하는지, 그리고 즉시 완화(quick mitigation)근본 해결(설계 변경) 을 단계별로 정리합니다. (예시는 EKS의 aws-vpc-cni를 중심으로 설명하지만, Calico/Cilium에서도 진단 흐름은 유사합니다.)

관련해서 노드가 NotReady로 떨어질 때 CNI/보안그룹/IRSA까지 함께 점검해야 하는 경우도 많습니다. 필요하면 이 글도 함께 참고하세요: Terraform apply 후 EKS 노드 NotReady - CNI·IRSA·보안그룹 점검

1) 증상: Pod는 Pending, 이벤트는 IP 할당 실패

1-1. Pod 상태 확인

kubectl get pod -A -o wide | grep Pending
kubectl describe pod -n <ns> <pod>

describeEvents에서 다음과 유사한 메시지가 보이면 IP 부족 가능성이 큽니다.

  • FailedCreatePodSandBox
  • failed to set up sandbox container / CNI failed to allocate IP
  • (EKS aws-vpc-cni) failed to assign an IP address to container

1-2. kubelet / CNI 로그에서 확인

노드에서 kubelet 로그 또는 CNI 데몬 로그를 확인합니다.

# 노드 접속 후
sudo journalctl -u kubelet -n 200 --no-pager

EKS의 경우 aws-node(aws-vpc-cni) DaemonSet 로그가 핵심입니다.

kubectl -n kube-system get pods -l k8s-app=aws-node -o wide
kubectl -n kube-system logs <aws-node-pod> -c aws-node --tail=200

대표적인 키워드:

  • IPAM / ipamd
  • AssignPodIPAddress 실패
  • datastore has no available IP addresses

2) 원인 구조: “노드당 Pod IP 풀”이 먼저 고갈된다

CNI IP 부족은 크게 두 층에서 발생합니다.

  1. 노드 레벨 고갈: 특정 노드가 보유한 Pod IP(secondary IP)가 부족해서 그 노드로 스케줄되는 Pod가 Pending
  2. 서브넷 레벨 고갈: 노드가 IP를 더 붙이려고 해도 VPC 서브넷에 남은 IP가 없어 전체적으로 할당 불가

EKS aws-vpc-cni 기준으로는 노드의 ENI(Elastic Network Interface)와 secondary IP가 Pod IP로 사용되기 때문에,

  • 인스턴스 타입별 ENI 개수/ENI당 IP 제한
  • WARM_IP_TARGET, MINIMUM_IP_TARGET 같은 사전 확보 설정
  • (최근 권장) Prefix delegation(/28) 사용 여부

에 따라 “노드당 수용 가능한 Pod 수”가 크게 달라집니다.

3) 빠른 확정 진단 체크리스트

3-1. Pending Pod가 특정 노드에만 몰리는가?

스케줄링은 되었는데 CNI에서 막히는 경우, describe pod에서 Node:가 찍히거나 Scheduled 이벤트는 성공한 상태일 수 있습니다.

kubectl describe pod -n <ns> <pod> | sed -n '/Events:/,$p'
  • Successfully assigned ... to ip-... 이후 FailedCreatePodSandBox가 나오면 노드 레벨 IP 부족 가능성이 큽니다.

3-2. 노드의 Pod 수 vs 인스턴스 타입 한계

kubectl get nodes
kubectl describe node <node> | egrep -i 'Pods:|Non-terminated Pods:|Allocatable|Capacity'

여기서 Capacity/Allocatablepods 값이 낮게 잡혀 있거나, 실제 파드 수가 한계에 근접하면 IP/ENI 제한에 걸릴 확률이 높습니다.

3-3. 서브넷 IP 잔량 확인(AWS)

서브넷 IP가 바닥나면 어떤 노드도 IP를 더 못 붙입니다.

aws ec2 describe-subnets --subnet-ids <subnet-1> <subnet-2> \
  --query 'Subnets[].{SubnetId:SubnetId,AvailableIpAddressCount:AvailableIpAddressCount,CidrBlock:CidrBlock}' \
  --output table

AvailableIpAddressCount가 매우 낮으면 서브넷 레벨 고갈이 원인입니다.

4) 즉시 완화(Quick Mitigation): 서비스 살리기

장애 상황에서는 “근본 해결”보다 지금 Pending을 풀어 트래픽을 받게 만드는 것이 우선입니다.

4-1. (노드 레벨) 노드 수를 늘려 IP 풀을 분산

클러스터 오토스케일러/노드그룹 스케일 아웃이 가장 빠르게 먹히는 경우가 많습니다.

  • 노드가 늘면 노드별로 ENI/secondary IP 풀도 늘어나므로 Pending이 해소될 수 있습니다.
  • 단, 서브넷 자체가 고갈이면 노드를 늘려도 소용이 없습니다.

4-2. (노드 레벨) 문제 노드 Drain 후 교체

특정 노드의 CNI가 꼬이거나 IP가 회수되지 않는(유령 IP) 상황이 겹치면 drain이 빠른 처방이 됩니다.

kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
# 노드 교체(ASG/EKS managed nodegroup에서 terminate)

4-3. (서브넷 레벨) 불필요한 Pod/Job 정리

짧게 끝나야 할 Job/배치가 누적되어 IP를 잡아먹는 경우가 있습니다.

kubectl get job -A
kubectl delete job -n <ns> <job>

kubectl get pod -A --field-selector=status.phase=Succeeded
kubectl delete pod -A --field-selector=status.phase=Succeeded

4-4. (EKS) WARM_IP_TARGET 상향으로 “미리 IP 확보”

이미 서브넷 여유가 있고, 단지 노드가 IP를 늦게 확보해서 순간적으로 Pending이 생긴다면 WARM_IP_TARGET/MINIMUM_IP_TARGET 튜닝이 효과적입니다.

kubectl -n kube-system set env daemonset aws-node \
  WARM_IP_TARGET=10 MINIMUM_IP_TARGET=10

kubectl -n kube-system rollout status ds/aws-node
  • 너무 크게 잡으면 노드들이 IP를 과도하게 선점하여 서브넷 고갈을 앞당길 수 있습니다.
  • 트래픽 패턴(스파이크)과 노드 수를 고려해 점진적으로 조정하세요.

5) 근본 해결: IP 설계/할당 방식을 바꿔야 재발이 줄어든다

5-1. 서브넷 CIDR 확장 또는 신규 서브넷 추가

서브넷 고갈이면 답은 명확합니다.

  • 더 큰 CIDR로 재설계(기존 서브넷 확장은 제약이 많음)
  • 신규 서브넷을 추가하고 노드그룹이 해당 서브넷을 사용하도록 변경

EKS에서는 노드그룹(또는 ASG)이 붙는 서브넷 목록을 늘려 IP 풀 자체를 확장하는 방식이 일반적입니다.

점검 포인트:

  • NAT Gateway/라우팅/보안그룹/NACL
  • 멀티 AZ 분산
  • 프라이빗/퍼블릭 서브넷 역할 분리

5-2. (EKS 권장) Prefix Delegation(/28)로 노드당 Pod 수 확대

aws-vpc-cni는 Prefix Delegation을 켜면 ENI에 개별 secondary IP를 하나씩 붙이는 대신 /28 프리픽스(16 IP) 단위로 할당받아 Pod IP를 더 효율적으로 운영할 수 있습니다.

설정은 환경/버전에 따라 다르지만, 일반적으로 ENABLE_PREFIX_DELEGATION=true를 사용합니다.

kubectl -n kube-system set env daemonset aws-node \
  ENABLE_PREFIX_DELEGATION=true

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

주의사항:

  • CNI 버전이 해당 기능을 안정적으로 지원하는지 확인
  • 인스턴스 타입/ENI 제한과 결합해 실제 증가 폭이 달라짐
  • Prefix를 쓰면 “노드가 서브넷에서 가져가는 IP 덩어리”가 커지므로 서브넷 설계가 더 중요해집니다.

5-3. 인스턴스 타입 변경: ENI/IP 한계가 낮은 타입 피하기

같은 노드 수여도 인스턴스 타입에 따라 Pod 수용량이 크게 갈립니다.

  • 작은 타입: ENI 수/ENI당 IP가 적어 Pod IP가 빨리 고갈
  • 큰 타입: 더 많은 ENI/IP로 Pod 밀도가 증가

실제로는 애플리케이션 리소스(CPU/메모리)보다 네트워크(IP) 가 먼저 병목이 되는 케이스가 많습니다.

5-4. 노드당 Pod 상한(--max-pods)과 CNI 설정의 정합성

노드가 이론상 IP를 더 붙일 수 있어도, kubelet의 --max-pods가 낮게 잡혀 있으면 과도한 스케줄링은 막히지만(그나마 안전), 반대로 --max-pods가 너무 높으면 스케줄러는 넣는데 CNI가 못 받쳐서 Pending 이 증가할 수 있습니다.

  • EKS AMI는 인스턴스 타입에 맞춰 maxPods를 계산해 주는 편이지만,
  • 커스텀 AMI/부트스트랩 옵션을 쓰면 불일치가 생길 수 있습니다.

5-5. (대안) 오버레이 CNI/Secondary Network 고려

VPC-native 방식이 IP를 너무 많이 소비한다면, 오버레이 네트워크(예: Calico overlay, Cilium overlay)로 전환하거나, 대규모 멀티테넌트 환경에서는 Secondary CIDR/추가 네트워크 인터페이스 설계도 검토합니다.

다만 이는 운영/보안/성능 특성이 달라지므로 PoC 후 단계적으로 진행하는 것이 안전합니다.

6) 재발 방지: 관측(Observability)과 운영 규칙

6-1. 서브넷 IP 잔량 알람

가장 먼저 해야 할 것은 서브넷 AvailableIpAddressCount 알람입니다.

  • CloudWatch(또는 외부 모니터링)로 임계치 경보
  • 예: 20% 이하 또는 절대값 256 이하 등, 환경에 맞게 설정

6-2. 노드 단위 IP 여유 모니터링

EKS라면 aws-node/ipamd 메트릭을 수집해 “노드별 남은 IP”를 시각화하세요.

  • 노드별 warm IP가 0에 수렴하는 패턴
  • 스케일 이벤트 직후 Pending 급증

6-3. 배치/크론잡의 Pod 누수 방지

Job이 끝났는데 Pod가 남아 IP를 점유하는 상황을 막기 위해 TTL을 적극 활용합니다.

apiVersion: batch/v1
kind: Job
metadata:
  name: sample-job
spec:
  ttlSecondsAfterFinished: 3600
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: worker
          image: busybox
          command: ["sh", "-c", "echo hello; sleep 5"]

7) 트러블슈팅 예시 시나리오(실전 흐름)

  1. kubectl get pod -A | grep Pending
  2. kubectl describe pod ...에서 FailedCreatePodSandBox + CNI IP 할당 실패 확인
  3. aws ec2 describe-subnets ...로 서브넷 IP 잔량 확인
    • 잔량 충분: 노드 레벨 문제(ENI/IP 한계, warm IP 부족, CNI 꼬임)
    • 잔량 부족: 서브넷/대역 설계 문제(확장/추가 필요)
  4. 즉시 완화: 노드 스케일 아웃 또는 drain/교체
  5. 근본 해결: 서브넷 확장/추가 + Prefix Delegation + 인스턴스 타입/max-pods 정합성 재검토

8) 마무리

Pod Pending은 원인이 다양하지만, CNI IP 부족은 “증상은 단순한데 원인은 설계(대역/인스턴스/할당 방식)에 걸쳐 있는” 대표적인 문제입니다. 장애 대응에서는 노드 확장/드레인으로 일단 불을 끄고, 이후에는 서브넷 IP 잔량 알람과 Prefix Delegation 같은 구조적 개선으로 재발을 줄이는 것이 정석입니다.

노드가 NotReady까지 동반하거나, CNI/보안그룹/IRSA 이슈가 섞여 원인이 복합적으로 보인다면 아래 글의 점검 순서가 도움이 됩니다.