본문 바로가기
Orchestration/Kubernetes

Amazon EKS 환경에서 신규 Subnet 할당을 통한 Pod IP 부족 문제 해결하기

by wlsdn3004 2024. 7. 11.
728x90
반응형

개요

Amazon EKS에서 Pod IP 부족 문제는 자주 발생하는 문제이다. 특히, EKS 클러스터의 기본 VPC에 할당된 Subnet의 CIDR 범위가 좁거나, 클러스터에 배포되는 Pod 수가 증가할 때 IP 부족 현상이 발생할 수 있다.

이러한 문제를 해결하기 위해 EKS에서 사용자 지정 네트워크를 기능을 활용하여 여러 Subnet의 CIDR 블록을 추가할 수 있다. 이를 통해 Pod에 할당할 수 있는 IP 주소를 확장하여 Pod 수가 많아지는 상황에서도 안정적으로 대응할 수 있다. 

 

사용자 지정 네트워크 설정 시 고려사항

  • 기본 ENI(Primary ENI)에 할당된 IP 주소는 Pod에 할당되지 않고, 오직 보조 ENI(Secondary ENI)에서 할당된 IP만 Pod에 할당된다. 단, 기존 Worker Node에는 기본 ENI에 할당된 IP 주소와 보조 ENI에 할당된 IP가 할당된다.
  • 클러스터가 IPv6을 사용하는 경우 사용자 지정 네트워크를 사용할 수 없다.
  • 보조 ENI가 배치되는 Subnet과 Security Group은 반드시 Node가 속한 VPC 내에서만 사용 가능하다.
  • Fargate에서 실행되는 Pod는 Fargate profiles을 통해 Subnet을 제어하므로, 사용자 지정 네트워크 설정이 아닌 Fargate 프로필을 통해 Subnet을 설정해야 한다.

 

구성을 하면 다음과 같은 구조가 된다.

 

만약, 보안상의 이유로 Worker Node와 Pod를 특정 네트워크에 격리해야 하는 경우 더 큰 Secondary CIDR 블록(예: 100.64.0.0/10)의 Subnet에 Worker Node와 Pod를 배포하는 것이 좋다. 

아래 그림에서는 사용자 지정 네트워킹이 사용되지 않는다. Worker Node는 100.64.0.0/10과 같은 VPC의 Secondary CIDR 대역의 Subnet에 배포되고, EKS 클러스터는 기존 Subnet을 사용한다. 해당 설정은 AWS Management Console에서 손쉽게 추가하여 설정할 수 있다.

  • (클러스터 설정) AWS Management Console > Amazon Elastic Kubernetes Service > Clusters > {클러스터 이름} > Networking > Manage VPC resources > {추가한 Subnet 선택 후 저장}
  • (Worker Node 설정) AWS Management Console > Amazon Elastic Kubernetes Service > Clusters > {클러스터 이름} > Compute > Add node group > {생성 과정에서 Subnet 선택 후 생성}

 

본 글에서는 사용자 지정 네트워크를 활용하여 VPC에 새로운 CIDR 대역을 추가하고 이를 기반으로 새로운 Subnet을 생성한 후, IP 부족 문제로 배포되지 못한 Pod가 새로 추가된 Subnet CIDR 대역을 할당받아 배포되는 과정을 실습을 통해 다룬다.

 

구성 환경

  • Amazon EKS v1.32.1

설치 버전

  • Amazon VPC CNI : v1.19.2-eksbuild.1

전제 조건

  • AWS 계정 및 권한
  • Amazon EKS 클러스터
  • kubectl CLI 도구

 

 


1. IP 부족 시나리오 재현

IP 부족 상황을 재현하기 위해, ENI가 할당할 수 있는 최대 개수 이상의 Pod를 배포하여 일부 Pod가 IP 부족으로 인해 구동되지 않는 상황을 만들어 볼 것이다.

현재 실습 환경은 EKS Worker Node가 2개이고, 각 Node는 1개의 ENI를 할당받아 사용하고 있다.

각 ENI는 최대 6개(t3.medium)를 IP를 할당받을 수 있어 전체 12개의 IP를 사용할 수 있다. 이 중 ENI 자체에서 사용하는 2개의 IP와 기본적으로 실행 중인 Pod 2개(CoreDNS) 총 4개가 이미 IP를 할당받아 사용하고 있다. 따라서 실제로 배포할 수 있는 Pod의 IP는 8개(12개 - 4개)가 된다.

 

이제 10개의 Pod를 배포하여, 2개의 Pod가 IP를 할당받지 못하는 상황을 의도적으로 만든다.

 

다음과 같이 10개의 nginx Pod를 배포한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 10  # Pod 복제본 개수
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

 

의도한 대로 10개의 nginx Pod 중 2개를 제외한 나머지 Pod는 정상적으로 구동되고 있다.

$ kubectl get po
NAME                              READY   STATUS              RESTARTS   AGE
nginx-deployment-96b9d695-29s52   1/1     Running             0          17m
nginx-deployment-96b9d695-8xcps   1/1     Running             0          17m
nginx-deployment-96b9d695-97x4x   1/1     Running             0          17m
nginx-deployment-96b9d695-9rg9x   0/1     ContainerCreating   0          17m
nginx-deployment-96b9d695-bm554   0/1     ContainerCreating   0          17m
nginx-deployment-96b9d695-bnx6s   1/1     Running             0          17m
nginx-deployment-96b9d695-g7xjk   1/1     Running             0          17m
nginx-deployment-96b9d695-hsp5g   1/1     Running             0          17m
nginx-deployment-96b9d695-lxp5t   1/1     Running             0          17m
nginx-deployment-96b9d695-pvkqv   1/1     Running             0          17m

 

구동되지 못한 Pod는 kubectl describe 명령어를 사용하여 IP 주소 할당에 실패했다는 메시지를 확인할 수 있다.

$ kubectl describe po nginx-deployment-96b9d695-9rg9x
#... 중략
Events:
  Type     Reason                  Age                   From               Message
  ----     ------                  ----                  ----               -------
  Normal   Scheduled               17m                   default-scheduler  Successfully assigned default/nginx-deployment-96b9d695-9rg9x to ip-10-0-1-12.ap-northeast-2.compute.internal
  Warning  FailedCreatePodSandBox  16m                   kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "65da0c935cdfab2cb530f10b90a8dbdaabfbd6a9261874c27080a217578f3d0a": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to assign an IP address to container
  Warning  FailedCreatePodSandBox  16m                   kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "8ebe55f3db88642ad18c147850df647443a229c28e3a37840fe8e91d5e8047bb": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to assign an IP address to container
  Warning  FailedCreatePodSandBox  2m53s (x62 over 16m)  kubelet            (combined from similar events): Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "0c5e58579069ce4421da337a2648440e2545639fd4f53443ca9e59dbb4b216eb": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to assign an IP address to container

 

 


2. 신규 Subnet 추가

VPC의 IP 주소 공간을 확장하기 위해 새로운 CIDR 대역을 추가한다.

주의

추가하려는 Secondary CIDR 대역은 TFC1918에서 정의한 사설 IP 대역을 사용할 수 없다.

CG-NAT 대역(100.64.0.0/10) 또는 198.19.0.0/16 대역은 RFC1918 대역보다 기업 환경에서 사용될 가능성이 적기 때문에, 해당 대역을 사용하는 것을 권장한다.

  • VPC > VPC 선택 체크 > Actions  > Edit CIDRs

 

다음과 같이 VPC에 포함된 모든 Subnet에 앞에서 추가한 CIDR 대역 라우팅 테이블 규칙이 추가된 것을 확인할 수 있다.

 

 다음과 같이 새로 추가한 CIDR 대역으로 신규 Subnet 2개를 생성한다.

 

 


3. Amazon VPC CNI 설정

aws-node 파드의 환경 변수를 변경하여 새로 추가한 Subnet을 사용할 수 있도록 설정해야 한다.

 

사용자 지정 네트워크 구성을 활성화한다

$ kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true

 

ENIConfig가 가용 영역에 해당하는 Worker Node의 Label을 식별하고 자동으로 적용될 수 있도록 Worker Node의 Label을 추가한다.

아래에서 설정하는 Label은 Worker Node가 생성될 때 자동으로 추가된다.

# Label 조회
$ kubectl get no --show-labels
NAME                                           STATUS   ROLES    AGE     VERSION               LABELS
ip-10-0-0-7.ap-northeast-2.compute.internal    Ready    <none>   22m     v1.32.1-eks-5d632ec   ...,topology.kubernetes.io/zone=ap-northeast-2a,...
ip-10-0-1-12.ap-northeast-2.compute.internal   Ready    <none>   6m40s   v1.32.1-eks-5d632ec   ...,topology.kubernetes.io/zone=ap-northeast-2b,...

# 조회한 Label 적용
$ kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone

 

 


4. ENIConfig 설정

ENIConfig 설정을 위해 먼저 CRD(Custom Resource Definition)가 생성되어 있어야 하는데, 만약 생성되어 있지 않다면 아래와 같이 kubectl 명령어를 이용하여 생성한다. ENIConfig CRD는 Amazon VPC CNI 플러그인이 특정 Subnet과 ENI에 대한 설정을 관리할 수 있도록 해준다. 이를 통해 각 가용 영역에 대해 특정 ENIConfig를 정의하고, Pod가 배포될 때 적절한 Subnet과 ENI가 자동으로 선택되도록 할 수 있다.

$ cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: eniconfigs.crd.k8s.amazonaws.com
spec:
  group: crd.k8s.amazonaws.com
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          x-kubernetes-preserve-unknown-fields: true
  scope: Cluster
  names:
    plural: eniconfigs
    singular: eniconfig
    kind: ENIConfig
    listKind: ENIConfigList
EOF

 

아래와 같이 ENIConfig 리소스를 정의하는 YAML 파일을 작성한다. 이 파일에서는 새로 생성된 Subnet의 ID를 입력한다.

$ cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
 name: ap-northeast-2a
spec:
  subnet: {새로 생성된 Subnet ID 1}
---
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
 name: ap-northeast-2b
spec:
  subnet: {새로 생성된 Subnet ID 2}
EOF

 

AWS 인스턴스의 Networking 탭에서 확인하면, 아래와 같이 기존에 할당된 IP와 새로 추가된 IP를 확인할 수 있다.

 

인스턴스의 Network Interfaces 정보를 보면, 추가된 Subnet 대역 IP가 할당된 ENI가 추가된 것을 확인할 수 있다.

 

이전 ContainerCreating 상태였던 Pod를 보면, 새로 추가한 Subnet 대역의 IP를 할당받아 정상 구동된 것을 확인할 수 있다. 

$ kubectl get po -o wide
NAME                              READY   STATUS    RESTARTS   AGE   IP               NODE                                           NOMINATED NODE   READINESS GATES
nginx-deployment-96b9d695-29s52   1/1     Running   0          43m   10.0.0.13        ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>
nginx-deployment-96b9d695-8xcps   1/1     Running   0          43m   10.0.0.4         ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>
nginx-deployment-96b9d695-97x4x   1/1     Running   0          43m   10.0.1.11        ip-10-0-1-12.ap-northeast-2.compute.internal   <none>           <none>
nginx-deployment-96b9d695-9rg9x   1/1     Running   0          43m   100.87.129.73    ip-10-0-1-12.ap-northeast-2.compute.internal   <none>           <none>
nginx-deployment-96b9d695-bm554   1/1     Running   0          43m   100.87.128.121   ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>
nginx-deployment-96b9d695-bnx6s   1/1     Running   0          43m   10.0.0.11        ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>
nginx-deployment-96b9d695-g7xjk   1/1     Running   0          43m   10.0.1.10        ip-10-0-1-12.ap-northeast-2.compute.internal   <none>           <none>
nginx-deployment-96b9d695-hsp5g   1/1     Running   0          43m   10.0.0.10        ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>
nginx-deployment-96b9d695-lxp5t   1/1     Running   0          43m   10.0.1.6         ip-10-0-1-12.ap-northeast-2.compute.internal   <none>           <none>
nginx-deployment-96b9d695-pvkqv   1/1     Running   0          43m   10.0.0.12        ip-10-0-0-7.ap-northeast-2.compute.internal    <none>           <none>

 

 


5. 참고 사항

설정을 마친 후 Worker Node를 그대로 사용하면 아래와 같이 Pod가 Primary ENI와 Secondary ENI를 모두 사용해서 두 개의 대역의 IP를 할당받을 수 있다.

아래 그림을 참고하자.

 

그러나 기존 Worker Node를 drain 후 새로운 Worker Node로 교체하면 Primary ENI의 IP는 노드 자체 용도로만 사용되고,  Pod는 오직 Secondary ENI에서만 IP를 할당받게 된다.

아래 그림을 참고하자.

 


마치며

사용자 지정 네트워크를 사용하면 IP 부족 문제를 해결할 수 있지만, 모든 문제를 해결할 수 있는 것은 아니다.
특히, 클러스터에서 이미 CG-NAT 대역을 사용하고 있거나, 클러스터 VPC에 보조 CIDR(Secondary CIDR)을 할당할 수 없는 경우, 다른 대안을 고려해야 한다.
이러한 상황에서는 다른 CNI(컨테이너 네트워크 인터페이스) 솔루션을 도입하거나, IPv6 클러스터로의 전환을 검토하는 것이 대안이 될 수 있다.

 

반응형

댓글