[EKS] CNI IP 관리 구조와 WARM 설정의 이해

xgro·2025년 11월 1일
0

EKS

목록 보기
6/6
post-thumbnail

📌 개요

최근 Amazon EKS 환경을 운영하면서 한 가지 흥미로운 문제를 마주했습니다.

“왜 파드가 25개까지만 생성되고, 그 이후부터는 IP를 더 이상 받지 못할까?”

처음엔 CNI 버그나 서브넷 한도 문제를 의심했지만,
원인은 생각보다 단순하면서도 많은 팀이 놓치기 쉬운 설정 조합에 있었습니다

  • MINIMUM_IP_TARGET과 WARM_IP_TARGET.

이 글은 EKS에서 AWS VPC CNI를 사용하는 환경에서,
“노드당 파드 IP가 갑자기 더 이상 늘어나지 않는 현상”을 경험한 운영자나 SRE, DevOps 엔지니어를 위한 기록입니다.

공식 문서에 조용히 숨어 있는 설정 간의 관계와 그 실제 동작 방식을 실험과 로그 분석을 통해 명확히 분석해보고자 합니다.


이 글을 읽고 나면 다음과 같은 인사이트를 얻을 수 있습니다.

  • CNI의 IP 관리 로직이 실제로 어떻게 동작하는지 (특히 WARM_IP_TARGET과 MINIMUM_IP_TARGET의 관계)
  • 왜 특정 조합에서는 ENI/IP 확장이 멈추는지, 그리고 그 현상을 로그와 introspection을 통해 어떻게 식별할 수 있는지

단순히 에러를 해결하는 방법을 넘어서,
AWS CNI의 내부 동작 원리를 이해하고 “문제의 원인을 체계적으로 추적하는 사고 과정”을 공유하고자 합니다.



📌 EKS에서 파드 IP가 결정되는 방식과 WARM 계열 설정의 의미

✅ EKS의 파드 네트워킹은 어떻게 동작하는가

Amazon EKS에서 파드는 노드(EC2 인스턴스)의 네트워크 인터페이스를 통해 VPC와 직접 연결됩니다.
이때 핵심 역할을 하는 구성요소가 바로 AWS VPC CNI 플러그인 입니다.

이 플러그인은 EC2 인스턴스에 부착된 ENI(Elastic Network Interface)의 보조 IPv4 주소(secondary IP) 를 관리하며, 파드에 고유한 IP를 할당합니다.

즉, 파드는 VPC의 기본 서브넷 주소를 직접 사용하며, NAT나 오버레이 없이 “VPC 네이티브 네트워킹”을 구현합니다.
이 구조 덕분에 네트워크 성능과 가시성이 뛰어나지만, 반대로 ENI와 IPv4 슬롯의 수가 노드당 파드 수의 상한을 결정짓는 중요한 요소가 됩니다.


✅ ENI와 IP 슬롯 — 인스턴스 타입이 결정하는 한계

각 EC2 인스턴스 타입은 지원하는 ENI 수와 ENI당 최대 IPv4 주소 수가 다릅니다.
링크 - https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/AvailableIpPerENI.html

예를 들어 m8g.4xlarge 인스턴스는 다음과 같습니다:

항목
최대 ENI 수8
ENI당 IPv4 주소 수30
총 할당 가능한 IPv4 수 (보조 IP 기준)8 × (30 - 1) = 232

하나의 ENI에는 1개의 기본(primary) IP가 노드 자신이 사용하고,
나머지 29개는 파드에 할당할 수 있는 보조 IP가 됩니다.

즉, ENI/IPv4 슬롯의 조합이 곧 “이 노드에서 파드를 몇 개까지 올릴 수 있는가”를 결정하게 됩니다.

여기에 kubelet 설정(maxPods)이 추가 제한으로 작동하며,
CNI와 kubelet이 서로 일관되지 않으면 IP가 남아 있어도 파드가 스케줄링되지 않는 경우가 발생할 수 있습니다.


✅ WARM 계열 설정의 역할 — 여유를 어떻게 관리할 것인가

AWS VPC CNI는 IP를 필요할 때마다 EC2 API를 호출해 추가 확보합니다.

그러나 ENI attachIP 할당은 수 초 단위의 지연이 발생할 수 있고,
EC2 API가 과도하게 호출될 경우 rate limit(호출 제한) 에 걸리기도 합니다.

이를 완화하기 위해 도입된 개념이 WARM 파라미터 입니다.
이는 “얼마나 여유롭게 ENI/IP를 확보해 둘 것인가”를 제어하는 파라미터 입니다.

변수역할설명
WARM_IP_TARGETIP 버퍼 유지량항상 지정된 개수의 ‘여유 IP’를 확보하도록 함
WARM_ENI_TARGETENI 버퍼 유지량ENI가 필요하기 전에 미리 attach하여 대기
MINIMUM_IP_TARGET초기 확보선노드가 최소 확보해야 하는 총 IP 개수
WARM_PREFIX_TARGETPrefix 모드 버퍼Prefix 모드(/28 블록 단위)에서 확보할 여유 블록 수

예를 들어 WARM_IP_TARGET=10이라면,
ipamd는 “언제나 10개의 미사용 IP가 남아 있도록” 유지하며,
파드가 늘어나면 즉시 새로운 ENI나 IP를 할당해 버퍼를 복원합니다.

이 설정이 없으면 파드 증가 시 EC2 API 호출이 실시간으로 발생하며, 네트워크 초기화 지연이 늘어나게 됩니다.


✅ Prefix Delegation 모드 — 대규모 노드의 필수 기능

기존의 개별 IP 관리 방식은 ENI 하나당 IP를 1개씩 EC2 API로 요청해야 합니다.
이 구조는 파드 스케일이 큰 워크로드에서 병목이 되기도 합니다.

AWS는 이를 개선하기 위해 Prefix Delegation 기능을 추가했습니다. (1.9.0+)

이 모드에서는 ENI가 /28 단위의 IP 블록(16개 주소)을 한 번에 확보합니다.
즉, API 호출 한 번으로 16개의 파드 IP를 확보하는 셈이 됩니다.

이를 활성화하면 ipamd의 동작 단위가 “IP 하나씩”에서 “Prefix 블록 단위”로 바뀌며,
WARM_PREFIX_TARGET을 이용해 여유 블록을 관리한다.

장점은 다음과 같습니다:

  • EC2 API 호출 횟수 대폭 감소 → 스케일아웃 시 지연 및 throttling 완화
  • ENI별 IP 확보 효율 향상 → 고밀도 노드에 적합

단점은:

  • /28 단위로 확보하므로 IP 낭비가 발생할 수 있음
  • 연속된 /28 블록을 확보해야 하므로 서브넷의 가용 주소 연속성이 중요

따라서, /28 블록 기준으로 서브넷을 설계하지 않은 환경에서는 Prefix 모드 활성화 시 IP fragmentation(단편화) 가능성을 고려해야 합니다.


📌 파드가 더 이상 생성되지 않는 이유 — AWS CNI의 내부 동작 분석

✅ 현상: 파드가 25개 이후부터 생성되지 않았다.

운영 중인 EKS 클러스터 노드에서 파드가 약 25개까지만 생성되고,
그 이후로는 모든 신규 파드가 ContainerCreating 상태에서 멈추는 현상이 발생했습니다.

이 시점의 kubectl describe pod 결과에는 다음과 같은 경고 로그가 반복적으로 출력되었습니다.

FailedCreatePodSandBox: rpc error: code = Unknown desc = failed to setup network for sandbox

node의 /var/log/aws-routed-eni/ipamd.log 로그 확인

AssignPodIPv4Address: no available IP/Prefix addresses
DataStore has no available IP/Prefix addresses

해당 오류는 AWS VPC CNI의 aws-node 데몬(내부적으로는 ipamd)이 파드에 할당할 가용 IP가 더 이상 없다고 판단했을 때 발생하는 메시지입니다.

흥미로운 점은, 같은 인스턴스 타입과 동일한 설정을 사용 중인 다른 클러스터에서는 50개 이상의 파드가 정상적으로 할당된다는 점이었습니다.

따라서 단순히 인스턴스 리소스의 한계나 서브넷 부족이 아닌, CNI의 내부 로직 차이가 의심되었습니다.


✅ ipamd의 내부 구조와 동작 흐름

AWS VPC CNI는 각 노드에서 실행되는 aws-node DaemonSet 내의 ipamd 프로세스가 실제 IP 관리 업무를 담당합니다.
ipamd의 기본 동작 순서는 다음과 같습니다.

  1. 파드 생성 요청 감지 (CNI ADD 호출)
    kubelet이 파드를 생성할 때 CNI 플러그인을 호출하면, ipamd는 내부 DataStore에서 사용 가능한 IP를 탐색합니다.

  2. DataStore 확인
    DataStore에는 “할당된 IP”, “미사용 IP”, “예비 IP”가 상태별로 저장되어 있습니다.

  3. 가용 IP 부족 시
    DataStore 내 Free IP가 없으면 ipamd가 EC2 API(AssignPrivateIpAddresses 또는 AssignIpv4Prefixes)를 호출해 새로운 IP를 확보합니다.

  4. IP 할당 및 DataStore 갱신
    새로 확보한 IP를 Pod에 할당하고, DataStore를 업데이트합니다.

  5. ENI 관리
    ENI별 IP 슬롯이 모두 소진되면, ipamd는 CreateNetworkInterface API를 호출하여 새로운 ENI를 부착합니다.

이 과정에서 EC2 API 호출은 WARM 설정의 트리거 조건에 따라 다르게 작동합니다.

  • WARM_IP_TARGET: 여유 IP가 이 값보다 작아지면 IP 추가 확보를 시도
  • WARM_ENI_TARGET: 여유 ENI가 부족하면 미리 attach
  • MINIMUM_IP_TARGET: 노드 초기 부팅 시 확보할 최소 IP 수

즉, ipamd는 파드 수에 따라 “동적으로 확장되는” 구조이며,
이 설정이 정상적으로 작동하지 않으면 IP 확보가 정지되는 현상이 발생합니다.


✅ 문제의 핵심 원인 — MINIMUM_IP_TARGET 단독 설정

문제의 노드에서 CNI 설정을 확인한 결과는 다음과 같았습니다.

MINIMUM_IP_TARGET=25
WARM_ENI_TARGET=1
WARM_IP_TARGET (미설정)

공식 문서에 따르면, 다음과 같은 동작이 명시되어 있습니다.

Links
If MINIMUM_IP_TARGET is set and WARM_IP_TARGET is not set,
WARM_IP_TARGET is assumed to be 0, which leads to the number of IPs attached to the node will be the value of MINIMUM_IP_TARGET.
This configuration will prevent future ENIs/IPs from being allocated.

즉, MINIMUM_IP_TARGET만 설정된 상태에서는 ipamd가 이미 목표치(25개)에 도달했다고 판단하여
더 이상 ENI 또는 IP 추가 요청을 수행하지 않습니다.


그 결과, DataStore의 상태는 다음과 같이 고정됩니다.

{
  "TotalIPs": 25,
  "AssignedIPs": 25
}

이 상태에서 새 파드가 스케줄되면 ipamd는 “할당 가능한 IP 없음”을 반환하게 되며,
결국 FailedCreatePodSandBox가 반복 발생합니다.


✅ CloudTrail 및 introspection 기반 검증

AWS CloudTrail 로그를 확인한 결과, 문제 발생 시점 이후에는
AssignPrivateIpAddresses API 호출이 전혀 관찰되지 않았습니다.
즉, ipamd가 새로운 IP 확보 시도를 중단한 상태였습니다.

반면 정상 동작하는 클러스터에서는 파드가 늘어날 때마다
다음과 같은 API 호출이 반복적으로 기록되었습니다.

{
  "eventName": "AssignPrivateIpAddresses",
  "requestParameters": {
    "networkInterfaceId": "eni-xxxxx",
    "secondaryPrivateIpAddressCount": 10
  }
}

추가로, aws-node 인스턴스 내부에서 introspection API(/v1/enis)를 확인한 결과
정상 노드에서는 여러 ENI가 부착되어 있었던 반면,
문제가 발생한 노드에서는 ENI가 하나뿐이었고, IP 슬롯이 모두 소진된 상태였습니다.

curl -s http://127.0.0.1:61679/v1/enis | jq
...
{
  "TotalIPs": 25,
  "AssignedIPs": 25,
  "ENIs": {
    "eni-xxx": {
      "ID": "eni-xxx",
      "IsPrimary": true,
...
}

이로써 ipamd가 ENI 확장을 시도하지 않았음을 명확히 확인할 수 있었습니다.


✅ 문제 해결 및 재현 실험

문제 해결은 매우 단순합니다.

WARM_IP_TARGET 값을 명시적으로 설정하면 ipamd가 IP 버퍼를 인식하고 자동으로 확장합니다.

kubectl -n kube-system set env ds/aws-node WARM_IP_TARGET=10
kubectl -n kube-system rollout restart ds/aws-node

설정 후 aws-node가 재시작되면 DataStore가 다시 초기화되고,
다음과 같이 IP가 확장되는 로그를 확인할 수 있습니다.

Trying to allocate additional IP addresses...
Calling EC2 API: AssignPrivateIpAddresses
Successfully assigned 10 IPs to eni-0abc1234...

Introspection 결과에서도 다음과 같이 IP 수가 증가합니다.

{
  "TotalIPs": 35,
  "AssignedIPs": 25
}

이제 ipamd는 파드 증가 시 ENI/IP를 자동으로 확장하며,
25개 이후 파드도 정상적으로 생성됩니다.



📌 Conclusion

EKS 환경에서 AWS VPC CNI는 매우 강력하고 편리한 네트워킹 솔루션입니다.

하지만 이번 사례처럼 단 한 줄의 파라미터(MINIMUM_IP_TARGET 단독 설정)로 인해
파드가 생성되지 않는 심각한 장애가 발생할 수 있습니다.

문제의 핵심은 MINIMUM_IP_TARGET을 단독으로 설정한 상태에서, WARM_IP_TARGET이 지정되지 않았다는 점이었습니다.
표면적으로는 단순히 IP 확보 개수를 정하는 파라미터처럼 보이지만, 실제로는 ipamd가 “얼마나 적극적으로 IP를 확장할 것인지”를 결정하는 기준이었습니다.

이 값이 0으로 간주되면 ipamd는 이미 충분한 IP를 보유하고 있다고 판단하여, 추가 ENI 생성이나 IP 확보를 중단하게 됩니다.
결국 시스템은 더 이상 파드를 위한 IP를 제공하지 못하고, 클러스터는 ‘할당 가능한 자원이 없음’ 상태로 정지하게 된 것입니다.

이 과정에서 중요한 사실은, 문제가 CNI의 버그나 네트워크 인프라의 한계 때문이 아니라, 설정 간의 관계를 오해한 운영 로직의 문제였다는 점입니다.

동일한 인스턴스 타입, 동일한 서브넷 구조에서도 설정 조합이 다르면 완전히 다른 결과를 만들어낼 수 있습니다.
이는 “EKS 네트워킹은 자동화되어 있지만, 완전히 추상화된 것은 아니다”라는 사실을 다시 한번 상기시켜 줍니다.

결국 “자동화된 시스템일수록 더 깊은 이해가 필요하다”는 것입니다.

EKS와 같은 완성도 높은 매니지드 서비스조차, 내부 구조와 의도된 설계 방향을 모르면 단 한 줄의 환경 변수 차이로 전체 워크로드의 동작이 멈출 수 있습니다.

설정 하나를 바꾸는 일은 사소해 보일 수 있지만, 그 이면에는 CNI가 가진 상태 기반 제어 로직, IP 할당 정책, ENI 관리 메커니즘이 함께 작동하고 있습니다.

profile
안녕하세요! DevOps 엔지니어 이재찬입니다. 블로그에 대한 피드백은 언제나 환영합니다! 기술, 개발, 운영에 관한 다양한 주제로 함께 나누며, 더 나은 협업과 효율적인 개발 환경을 만드는 과정에 대해 인사이트를 나누고 싶습니다. 함께 여행하는 기분으로, 즐겁게 읽어주시면 감사하겠습니다! 🚀

0개의 댓글