Published on

EKS Pod Pending - CNI IP 고갈 해결법

Authors

EKS를 운영하다 보면 어느 날부터 신규 배포가 멈추고 Pod가 Pending 상태로 고착되는 상황을 마주합니다. 노드는 Ready인데도 스케줄링이 안 되고, 이벤트에는 FailedCreatePodSandBox 또는 failed to assign an IP address to container 류의 메시지가 반복됩니다. 이때 가장 흔한 원인이 AWS VPC CNI의 IP 고갈입니다.

이 글에서는 “왜 IP가 고갈되는지”, “어디서 확인해야 하는지”, “지금 당장 살리는 응급 처치”와 “재발을 막는 구조적 해결”을 순서대로 정리합니다.

관련해서 리소스가 남는데도 갑자기 막히는 고갈 문제의 감각은 inode 고갈과도 유사합니다. 패턴 자체가 비슷하니 함께 읽어보면 원인 파악 속도가 빨라집니다: 용량 남는데 No space left? inode 고갈 해결법

증상: Pod는 Pending, 노드는 멀쩡해 보인다

대표적인 징후는 다음과 같습니다.

  • kubectl get pods 에서 특정 네임스페이스/워크로드가 대량 Pending
  • kubectl describe pod ... 이벤트에 아래와 유사한 메시지
    • FailedCreatePodSandBox
    • failed to assign an IP address to container
    • add cmd: failed to assign an IP address to container
  • 노드 수는 충분하고 kubectl get nodes 는 모두 Ready
  • 클러스터 오토스케일러가 있어도 효과가 없거나, 노드가 늘어도 여전히 Pending

핵심은 스케줄링 이전이 아니라, Pod 네트워크(IP 할당) 단계에서 막힌다는 점입니다.

원리: AWS VPC CNI는 Pod에 VPC IP를 할당한다

EKS 기본 네트워킹(aws-vpc-cni)은 각 Pod에 VPC의 사설 IP를 할당합니다. 즉, Pod 수는 곧 VPC 서브넷의 IP 소비량입니다.

여기서 IP 고갈이 발생하는 주요 이유는 다음 중 하나(또는 조합)입니다.

  1. 서브넷 CIDR이 작다
  2. 노드당 할당 가능한 Pod 수가 인스턴스 ENI/IP 한도에 의해 제한된다
  3. CNI가 미리 확보해두는 warm IP/ENI가 많아 실제 사용량보다 빨리 고갈된다
  4. 노드가 분산되지 않고 특정 서브넷/AZ에 쏠려 한쪽만 고갈된다
  5. 대량 배포/스파이크로 순간적으로 IP를 빠르게 소진한다

1차 진단: Pod 이벤트와 CNI 로그로 확정하기

Pod 이벤트 확인

kubectl describe pod -n your-ns your-pod

이벤트에서 FailedCreatePodSandBox 와 함께 IP 할당 실패 메시지가 보이면 CNI IP 고갈 가능성이 큽니다.

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

kubectl -n kube-system get pods -l k8s-app=aws-node
kubectl -n kube-system logs -l k8s-app=aws-node -c aws-node --tail=200

로그에서 AssignPodIPv4Address 실패, InsufficientCidrBlocks 또는 IP 풀 고갈을 암시하는 문구가 반복되면 거의 확정입니다.

노드별 Pod 수와 한도 감 잡기

노드에 Pod가 어느 정도 붙어 있는지부터 확인합니다.

kubectl get nodes -o wide
kubectl get pods -A -o wide --field-selector spec.nodeName=YOUR_NODE

노드당 Pod가 특정 수에서 더 이상 늘지 않는다면, 인스턴스 타입의 ENI/IP 한도 또는 CNI 설정이 병목일 수 있습니다.

2차 진단: 서브넷 IP 가용량 확인

VPC 서브넷의 남은 IP가 실제로 부족한지 확인해야 합니다.

AWS CLI로 서브넷 가용 IP 확인

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

AvailableIpAddressCount 가 급격히 낮거나 0에 가까우면 원인이 명확합니다.

특정 AZ/서브넷 쏠림 체크

노드가 어떤 서브넷에 붙어 있는지(= 어떤 AZ에 몰렸는지)도 중요합니다. 한 서브넷만 고갈되면, 다른 서브넷에 IP가 남아도 해당 서브넷에 뜨는 노드는 Pod를 못 받습니다.

aws ec2 describe-instances \
  --filters Name=tag:eks:cluster-name,Values=YOUR_CLUSTER \
  --query 'Reservations[].Instances[].{InstanceId:InstanceId,SubnetId:SubnetId,AZ:Placement.AvailabilityZone,PrivateIp:PrivateIpAddress}' \
  --output table

응급 처치: 지금 Pending을 풀어야 할 때

아래 방법들은 “근본 해결”이라기보다 서비스를 먼저 살리는 방법입니다.

방법 1) 노드 스케일 아웃(단, 다른 서브넷/AZ로 퍼질 때만 유효)

클러스터 오토스케일러나 노드그룹 스케일 아웃으로 새 노드를 늘리면, 새 노드가 IP가 남아 있는 서브넷에 뜨는 경우 Pending이 풀릴 수 있습니다.

하지만 이미 모든 서브넷이 고갈이거나, 스케일 아웃이 같은 서브넷으로만 발생하면 효과가 없습니다.

방법 2) 불필요한 Pod 종료로 IP 즉시 회수

가장 빠르게 IP를 회수하는 방법은 불필요한 워크로드를 줄이는 것입니다.

kubectl scale deploy -n your-ns some-batch --replicas=0

또는 HPA/배치 워크로드가 순간 폭증한 경우 상한을 낮춰 스파이크를 줄입니다.

방법 3) CNI warm IP/ENI 설정을 낮춰 “선점”을 줄이기

aws-vpc-cni는 성능을 위해 미리 IP를 확보해두는 전략을 씁니다. 이 값이 너무 크면 실제 Pod 수보다 더 많은 IP를 잡아먹어 고갈을 앞당깁니다.

아래는 대표적인 환경 변수들입니다(클러스터/버전에 따라 사용 가능 옵션이 다를 수 있습니다).

  • WARM_IP_TARGET
  • MINIMUM_IP_TARGET
  • WARM_ENI_TARGET

예시로 WARM_IP_TARGET 을 낮추는 패치:

kubectl -n kube-system set env daemonset/aws-node WARM_IP_TARGET=5
kubectl -n kube-system rollout status daemonset/aws-node

주의:

  • 값을 너무 낮추면 Pod 생성 지연이 늘 수 있습니다.
  • 이미 고갈된 상태에서는 “선점 감소”만으로는 즉시 회복이 제한적일 수 있습니다(가용 IP 자체가 없으면 해결 불가).

근본 해결 1: 서브넷 CIDR 확장 또는 추가 서브넷 구성

가장 확실한 해결은 Pod가 사용할 IP 풀 자체를 키우는 것입니다.

선택지 A) 서브넷에 IPv4 CIDR 추가(Secondary CIDR)

VPC/서브넷에 보조 CIDR을 추가해 IP를 늘릴 수 있습니다. 다만 기존 리소스와 라우팅, 조직의 네트워크 정책에 영향을 줄 수 있어 변경 관리가 필요합니다.

선택지 B) 더 큰 서브넷으로 재구성

운영 중인 서브넷을 “그대로 크게” 만들 수는 없기 때문에 보통은 새 서브넷을 만들고 노드그룹을 점진적으로 옮기는 식으로 진행합니다.

권장 방향:

  • AZ마다 최소 1개 이상, 가능하면 2개 이상의 워커 서브넷
  • 향후 Pod 증가를 고려해 충분히 큰 CIDR(예: /19, /18 등)
  • NAT, 라우팅 테이블, 보안그룹, NACL 정책 동기화

근본 해결 2: Prefix Delegation 활성화로 IP 효율 개선

AWS VPC CNI는 IPv4 prefix delegation(프리픽스 위임)을 지원합니다. 이를 켜면 ENI에 개별 IP를 주렁주렁 붙이는 대신, /28 같은 프리픽스를 할당받아 Pod IP를 더 효율적으로 운용할 수 있습니다.

효과:

  • 노드당 더 많은 Pod를 수용 가능(인스턴스/환경에 따라 체감 큼)
  • IP 할당/회수 오버헤드 감소

활성화 예시(환경에 따라 키 이름/지원 여부가 다를 수 있으니 적용 전 CNI 문서와 버전 확인 필요):

kubectl -n kube-system set env daemonset/aws-node ENABLE_PREFIX_DELEGATION=true
kubectl -n kube-system set env daemonset/aws-node WARM_PREFIX_TARGET=1
kubectl -n kube-system rollout status daemonset/aws-node

운영 팁:

  • 먼저 aws-node 애드온 버전이 prefix delegation을 안정적으로 지원하는지 확인합니다.
  • 롤아웃 후 신규 노드부터 효과가 잘 나타나는 편이라, 노드 롤링 교체 전략과 함께 계획하는 게 안전합니다.

근본 해결 3: 노드 분산(서브넷/AZ)과 스케줄링 편향 제거

IP가 남아 있는 서브넷이 있어도, 노드가 특정 AZ에 편향되면 고갈이 반복됩니다.

점검 포인트:

  • 노드그룹이 여러 서브넷을 참조하는지
  • 클러스터 오토스케일러가 특정 AZ만 선호하도록 설정되어 있지 않은지
  • topologySpreadConstraints, podAntiAffinity 등으로 Pod 분산을 유도할 필요가 있는지

예시로 topology spread를 걸어 AZ 쏠림을 줄이는 형태(개념 예시):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 12
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: api
      containers:
        - name: api
          image: your-image

whenUnsatisfiableDoNotSchedule 로 두면 가용 리소스가 있어도 스케줄링이 막힐 수 있으니, 상황에 맞게 선택합니다.

근본 해결 4: Pod IP를 “덜 쓰는” 아키텍처 고려

VPC CNI 모델에서는 Pod 수가 곧 IP 수요입니다. 아래 상황이라면 구조적으로 IP 수요를 줄이는 것도 고려할 가치가 있습니다.

  • 짧게 뜨고 사라지는 Job/배치가 매우 많다
  • 트래픽 스파이크 때 HPA가 크게 튄다
  • 멀티 테넌시로 네임스페이스/팀이 늘어 Pod 수가 빠르게 증가한다

대안 아이디어:

  • 배치 워크로드는 큐 기반으로 동시성 상한을 둬서 스파이크를 완화
  • 필요 이상으로 잘게 쪼개진 마이크로서비스를 합리적으로 통합
  • 노드 리소스가 남는데 IP만 부족한 형태라면 prefix delegation 및 서브넷 확장이 우선

스파이크/큐 지연/재시도 같은 운영 설계는 네트워크 자원에도 직접적인 영향을 줍니다. 대량 요청을 다루는 관점은 다음 글과도 맞닿아 있습니다: OpenAI Batch API 429·큐 지연·부분실패 재시도 전략

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

1) 서브넷 가용 IP 모니터링

  • CloudWatch 또는 외부 모니터링에 AvailableIpAddressCount 알람
  • 임계치 예: 20% 이하 또는 절대값 100 이하 등(환경에 맞게)

2) CNI 메트릭/로그 상시 수집

  • aws-node 로그에서 IP 할당 실패 카운트
  • 노드별 Pod 생성 실패 이벤트

3) 배포 이벤트와 IP 감소의 상관관계 기록

릴리스 직후 IP가 급감한다면 다음을 의심합니다.

  • HPA 최소/최대값 과대
  • 카나리/블루그린 시 구버전+신버전 동시 구동으로 Pod 2배
  • PDB로 인해 오래된 Pod가 늦게 내려가 IP 회수가 지연

빠른 트러블슈팅 런북(요약)

  1. kubectl describe pod 로 IP 할당 실패 이벤트 확인
  2. aws-node 로그에서 CNI IP 할당 실패 확인
  3. describe-subnets 로 서브넷 AvailableIpAddressCount 확인
  4. 응급: 불필요 Pod 축소, 노드 분산 스케일 아웃, warm IP 타겟 조정
  5. 근본: 서브넷 확장/추가, prefix delegation 활성화, AZ/서브넷 분산 설계

마무리

EKS에서 Pod Pending 은 원인이 다양하지만, “노드는 건강한데 Pod만 안 뜬다”와 “샌드박스 생성 실패 + IP 할당 실패” 조합이면 CNI IP 고갈을 최우선으로 의심하는 게 맞습니다. 응급 처치로 시간을 벌되, 결국은 서브넷 설계와 CNI 설정(prefix delegation 포함) 을 손봐야 같은 장애가 반복되지 않습니다.

추가로 EKS 운영에서 네트워크/인프라 계층 이슈가 애플리케이션 장애처럼 보이는 경우가 많습니다. 비슷한 결의 EKS 트러블슈팅 사례로는 다음 글도 참고할 만합니다: EKS에서 413 없이 502? gRPC 최대 메시지 해결