KANS3 - 9주차 AWS EKS : VPC CNI…

김성중·2024년 11월 1일
1
post-thumbnail

KANS(Kubernetes Advanced Networking Study) 3기 과정으로 학습한 내용을 정리 또는 실습한 정리한 게시글입니다. 마지막 9주차는 AWS EKS에서 기본적으로 사용하는 VPC CNI를 학습하였고 이에 대한 정리입니다. EKS 운영하면서 Pod IP 할당안되 노드 Scale-Out 실패 문제 해결사례를 정리하였습니다.

아래 EKS VPC CNI는 Amazon EKS Best Practices Guide 문서의 Amazon VPC CNI(https://docs.aws.amazon.com/eks/latest/best-practices/vpc-cni.html) 공식 문서를 되새김질하는 마음으로 내용을 재 정리하였습니다.

1. EKS VPC CNI

Amazon EKS는 Amazon VPC 컨테이너 네트워크 인터페이스를 통해 클러스터 네트워킹을 구현합니다. 플러그인, VPC CNI라고도 합니다. CNI 플러그인을 사용하면 Kubernetes Pod가 VPC 네트워크 동일한 IP 주소를 가질 수 있습니다. 더 구체적으로, Pod 내부의 모든 컨테이너는 네트워크 네임스페이스를 공유하며 로컬 포트를 사용하여 서로 통신할 수 있습니다.

Amazon VPC CNI에는 두 가지 구성 요소가 있습니다.

  • CNI Binary: Pod-to-Pod 통신을 활성화하기 위해 Pod 네트워크를 설정합니다. CNI Binary는 노드 root filesystem에서 실행되며 새 Pod가 노드에 추가되거나 기존 Pod가 노드에서 제거될 때 kubelet에서 호출됩니다.
  • ipamd는 장기 실행 노드 로컬 IP 주소 관리(IPAM) 데몬이며 다음을 담당합니다.
    • 노드에서 ENI 관리 및
    • 사용 가능한 IP 주소 또는 접두사의 warm-pool 유지

인스턴스가 생성되면 EC2는 Primary Subnet과 연관된 Primary ENI를 생성하여 연결합니다. Primary Subnet은 Public 또는 Private일 수 있습니다. hostNetwork 모드에서 실행되는 Pod는 노드 기본 ENI에 할당된 기본 IP 주소를 사용하고 호스트와 동일한 네트워크 네임스페이스를 공유합니다.

CNI 플러그인은 노드에서 ENI(Elastic Network Interfaces를 관리합니다. 노드가 프로비저닝되면 CNI 플러그인은 노드의 서브넷에서 기본 ENI로 슬롯 풀(IP 또는 접두사)을 자동으로 할당합니다. 이 풀은 warm pool 이라고 하며, 크기는 노드의 인스턴스 유형에 따라 결정됩니다. CNI 설정에 따라 슬롯은 IP 주소 또는 접두사가 될 수 있습니다. ENI의 슬롯이 할당되면 CNI는 슬롯의 warm pool이 있는 추가 ENI를 노드에 연결할 수 있습니다. 이러한 추가 ENI를 보조 ENI라고 합니다. 각 ENI는 인스턴스 유형에 따라 특정 수의 슬롯만 지원할 수 있습니다. CNI는 일반적으로 Pod 수에 해당하는 필요한 슬롯 수에 따라 인스턴스에 더 많은 ENI를 연결합니다. 이 프로세스는 노드가 더 이상 추가 ENI를 지원할 수 없을 때까지 계속됩니다. CNI는 또한 더 빠른 Pod 시작을 위해 "warm" ENI와 슬롯을 미리 할당합니다. 각 인스턴스 유형에는 연결할 수 있는 최대 ENI 수가 있습니다. 이는 컴퓨팅 리소스 외에도 Pod 밀도(노드당 Pod 수)에 대한 제약 조건 중 하나입니다.

새로운 ENI 위임 접두사가 필요한 경우의 절차를 설명하는 흐름도

네트워크 인터페이스의 최대 수와 사용할 수 있는 슬롯의 최대 수는 EC2 인스턴스의 유형에 따라 다릅니다. 각 Pod는 슬롯에서 IP 주소를 사용함으로 특정 EC2 인스턴스에서 실행할 수 있는 Pod 수는 연결할 수 있는 ENI 수와 각 ENI가 지원하는 슬롯 수에 따라 달라집니다. 인스턴스의 CPU 및 메모리 리소스가 고갈되는 것을 방지하기 위해 EKS 사용자 가이드당 최대 Pod 수를 설정하는 것이 좋습니다. 사용하는 Pod는 이 계산에서 제외됩니다. max-pod-calculator.shhostNetwork 라는 스크립트를 사용하는 것을 고려할 수 있습니다. 주어진 인스턴스 유형에 대해 EKS가 권장하는 최대 Pod 수를 계산합니다.

1.1 개요

보조 IP 모드는 VPC CNI의 기본 모드입니다. 이 가이드는 보조 IP 모드가 활성화된 경우 VPC CNI 동작에 대한 일반적인 개요를 제공합니다. ipamd(IP 주소 할당)의 기능은 Linux용 접두사 모드 , Pod당 보안 그룹 , 사용자 지정 네트워킹 과 같은 VPC CNI의 구성 설정에 따라 달라질 수 있습니다 .

Amazon VPC CNI는 워커 노드에 aws-node라는 Kubernetes Daemonset으로 배포됩니다. 워커 노드가 프로비저닝되면 기본 ENI인 기본 ENI가 연결됩니다. CNI는 노드의 기본 ENI에 연결된 서브넷에서 ENI와 보조 IP 주소의 warm pool을 할당합니다. 기본적으로 ipamd는 노드에 추가 ENI를 할당하려고 시도합니다. IPAMD는 단일 Pod가 예약되고 기본 ENI에서 보조 IP 주소가 할당되면 추가 ENI를 할당합니다. 이 "warm" ENI는 더 빠른 Pod 네트워킹을 가능하게 합니다. 보조 IP 주소 풀이 소진되면 CNI는 다른 ENI를 추가하여 더 많이 할당합니다.

풀의 ENI 및 IP 주소 수는 WARM_ENI_TARGET, WARM_IP_TARGET, MINIMUM_IP_TARGET 이라는 환경 변수를 통해 구성됩니다. aws-nodeDaemonset은 충분한 수의 ENI가 Attached 되었는지 주기적으로 확인합니다. 모든 WARM_ENI_TARGET, 또는 WARM_IP_TARGETMINIMUM_IP_TARGET 조건이 충족되면 충분한 수의 ENI가 첨부됩니다. 첨부된 ENI가 충분하지 않으면 CNI는 EC2에 API 호출을 수행하여 MAX_ENI 한계에 도달할 때까지 더 첨부합니다.

  • WARM_ENI_TARGET- 정수, 0보다 큰 값은 요구 사항 활성화를 나타냅니다.

    • 유지해야 할 Warm ENI의 수. ENI는 노드에 보조 ENI로 연결되지만 어떤 Pod에서도 사용되지 않을 때 "warm"입니다. 더 구체적으로 말하면, ENI의 IP 주소가 Pod와 연결되지 않았습니다.
    • 예: 2개의 ENI가 있는 인스턴스를 고려합니다. 각 ENI는 5개의 IP 주소를 지원합니다. WARM_ENI_TARGET은 1로 설정됩니다. 정확히 5개의 IP 주소가 인스턴스와 연결된 경우 CNI는 인스턴스에 연결된 2개의 ENI를 유지합니다. 첫 번째 ENI는 사용 중이며 이 ENI의 모든 5개 가능한 IP 주소가 사용됩니다. 두 번째 ENI는 풀에 모든 5개 IP 주소가 있는 "웜" 상태입니다. 인스턴스에서 다른 Pod가 시작되면 6번째 IP 주소가 필요합니다. CNI는 이 6번째 Pod에 두 번째 ENI와 풀의 5개 IP에서 IP 주소를 할당합니다. 두 번째 ENI는 현재 사용 중이며 더 이상 "웜" 상태가 아닙니다. CNI는 최소 1개의 웜 ENI를 유지하기 위해 3번째 ENI를 할당합니다.

      warm ENI는 여전히 VPC의 CIDR에서 IP 주소를 사용합니다.
      IP 주소는 Pod와 같은 워크로드와 연결될 때까지 "unused" 또는 "warm" 상태입니다.

  • WARM_IP_TARGET, 정수, 0보다 큰 값은 요구 사항을 나타냅니다. 활성화됨

    • 유지해야 할 Warm IP 주소의 수. Warm IP는 활성 연결된 ENI에서 사용할 수 있지만 Pod에 할당되지 않았습니다. 즉, 사용 가능한 Warm IP의 수는 추가 ENI가 필요 없이 Pod에 할당할 수 있는 IP의 수입니다.
    • 예: 1개의 ENI가 있는 인스턴스를 고려합니다. 각 ENI는 20개의 IP 주소를 지원합니다. WARM_IP_TARGET은 5로 설정됩니다. WARM_ENI_TARGET은 0으로 설정됩니다. 16번째 IP 주소가 필요할 때까지 1개의 ENI만 연결됩니다. 그런 다음 CNI는 두 번째 ENI를 연결하여 서브넷 CIDR에서 가능한 20개의 주소를 사용합니다.
  • MINIMUM_IP_TARGET, 정수, 0보다 큰 값은 요구 사항을 나타냅니다. 활성화됨

    • 언제든지 할당할 수 있는 최소 IP 주소 수입니다. 이는 일반적으로 인스턴스 시작 시 여러 ENI 할당을 미리 로드하는 데 사용됩니다.
    • 예: 새로 시작된 인스턴스를 생각해 보세요. ENI가 1개이고 각 ENI는 IP 주소 10개를 지원합니다. MINIMUM_IP_TARGET은 100으로 설정됩니다. ENI는 즉시 9개의 ENI를 더 연결하여 총 100개의 주소를 만듭니다. 이는 WARM_IP_TARGET 또는 WARM_ENI_TARGET 값과 관계없이 발생합니다.

서브넷 계산기 Excel 문서는 WARM_IP_TARGETWARM_ENI_TARGET 같은 다양한 ENI 구성 옵션에서 지정된 workload의 IP 주소 소비를 시뮬레이션합니다.

포드에 IP 주소를 할당하는 데 관련된 구성 요소의 그림

Kubelet이 Pod 추가 요청을 받으면 CNI 바이너리(VPC CNI)는 ipamd에 사용 가능한 IP 주소를 쿼리하고, ipamd는 이를 Pod에 제공합니다. CNI 바이너리는 호스트와 Pod 네트워크를 연결합니다.

노드에 배포된 Pod는 기본적으로 기본 ENI와 동일한 보안 그룹에 할당됩니다. 또는 Pod는 다른 보안 그룹으로 구성될 수 있습니다.

포드에 IP 주소를 할당하는 데 관련된 구성 요소의 두 번째 그림

IP 주소 풀이 고갈되면 플러그인은 자동으로 다른 탄력적 네트워크 인터페이스를 인스턴스에 연결하고 해당 인터페이스에 또 다른 보조 IP 주소 세트를 할당합니다. 이 프로세스는 노드가 더 이상 추가 탄력적 네트워크 인터페이스를 지원할 수 없을 때까지 계속됩니다.

포드에 IP 주소를 할당하는 데 관련된 구성 요소의 세 번째 그림

Pod가 삭제되면 VPC CNI는 Pod의 IP 주소를 30초 쿨다운 캐시에 저장합니다. 쿨다운 캐시의 IP는 새 Pod에 할당되지 않습니다. 쿨링오프 기간이 끝나면 VPC CNI는 Pod IP를 다시 웜 풀로 옮깁니다. 쿨링오프 기간은 Pod IP 주소가 조기에 재활용되는 것을 방지하고 모든 클러스터 노드의 kube-proxy가 iptables 규칙 업데이트를 완료할 수 있도록 합니다. IP 또는 ENI 수가 웜 풀 설정 수를 초과하면 ipamd 플러그인은 IP와 ENI를 VPC로 반환합니다.

위에서 설명한 대로 보조 IP 모드에서 각 Pod는 인스턴스에 연결된 ENI 중 하나에서 보조 개인 IP 주소 하나를 받습니다. 각 Pod는 IP 주소를 사용하므로 특정 EC2 인스턴스에서 실행할 수 있는 Pod 수는 연결할 수 있는 ENI 수와 지원하는 IP 주소 수에 따라 달라집니다. VPC CNI는 제한을 확인합니다. 각 인스턴스 유형에 허용되는 ENI와 IP 주소의 수를 파악하려면 위 링크의 Excel 파일을 사용하세요.

다음 공식을 사용하면 노드에 배포할 수 있는 최대 Pod 수를 결정할 수 있습니다.

(인스턴스 유형의 네트워크 인터페이스 수 * (네트워크 인터페이스당 IP 주소 수 - 1)) + 2

+2는 kube-proxy 및 VPC CNI와 같은 호스트 네트워킹이 필요한 Pod를 나타냅니다. Amazon EKS는 각 노드에서 kube-proxy 및 VPC CNI가 작동해야 하며 이러한 요구 사항은 max-pods 값에 반영됩니다. 추가 호스트 네트워킹 Pod를 실행하려면 max-pods 값을 업데이트하는 것을 고려하세요.

+2는 kube-proxy 및 VPC CNI와 같은 호스트 네트워킹을 사용하는 Kubernetes Pod를 나타냅니다. Amazon EKS는 모든 노드에서 kube-proxy 및 VPC CNI가 실행되어야 하며 max-pods에 대해 계산됩니다. 호스트 네트워킹 Pod를 더 많이 실행하려는 경우 max-pods를 업데이트하는 것을 고려하세요. --kubelet-extra-args "—max-pods=110"시작 템플릿에서 사용자 데이터로 지정할 수 있습니다.

예를 들어, 3개의 c5.large 노드(3개의 ENI와 ENI당 최대 10개의 IP)가 있는 클러스터에서 클러스터가 시작되고 2개의 CoreDNS 포드가 있는 경우 CNI는 49개의 IP 주소를 소비하고 이를 웜 풀에 보관합니다. 웜 풀은 애플리케이션이 배포될 때 더 빠른 포드 시작을 가능하게 합니다.

  • 노드 1(CoreDNS 포드 포함): 2개 ENI, 20개 IP 할당됨
  • 노드 2(CoreDNS 포드 포함): 2개 ENI, 20개 IP 할당됨
  • 노드 3(Pod 없음): ENI 1개. IP 10개 할당됨.

종종 데몬 세트로 실행되는 인프라 포드는 각각 최대 포드 수에 기여한다는 점을 명심하세요. 여기에는 다음이 포함될 수 있습니다.

  • CoreDNS
  • Amazon Elastic LoadBalancer
  • Operational pods for metrics-server

이러한 Pod의 용량을 결합하여 인프라를 계획하는 것이 좋습니다. 각 인스턴스 유형에서 지원하는 최대 Pod 수 목록은 GitHub eni-max-Pods.txt 를 참조하세요.

노드에 연결된 여러 ENI의 그림

1.2 추천사항

VPC CNI 관리형 애드온 배포

클러스터를 프로비저닝하면 Amazon EKS가 VPC CNI를 자동으로 설치합니다. 그럼에도 불구하고 Amazon EKS는 클러스터가 컴퓨팅, 스토리지, 네트워킹과 같은 기본 AWS 리소스와 상호 작용할 수 있도록 하는 관리형 애드온을 지원합니다. VPC CNI를 포함한 관리형 애드온이 있는 클러스터를 배포하는 것이 좋습니다.

Amazon EKS 관리형 애드온은 Amazon EKS 클러스터에 대한 VPC CNI 설치 및 관리를 제공합니다. Amazon EKS 애드온에는 최신 보안 패치, 버그 수정이 포함되어 있으며 AWS에서 Amazon EKS와 함께 작동하도록 검증되었습니다. VPC CNI 애드온을 사용하면 Amazon EKS 클러스터의 보안과 안정성을 지속적으로 보장하고 애드온을 설치, 구성 및 업데이트하는 데 필요한 노력을 줄일 수 있습니다. 또한 관리형 애드온은 Amazon EKS API, AWS Management Console, AWS CLI 및 eksctl을 통해 추가, 업데이트 또는 삭제할 수 있습니다.

kubectl get--show-managed-fields 명령 에 플래그를 사용하여 VPC CNI의 관리되는 필드를 찾을 수 있습니다.

kubectl get daemonset aws-node --show-managed-fields -n kube-system -o yaml

관리되는 애드온은 15분마다 구성을 자동으로 덮어써서 구성 드리프트를 방지합니다. 즉, 애드온 생성 후 Kubernetes API를 통해 관리되는 애드온에 대한 모든 변경 사항은 자동화된 드리프트 방지 프로세스에 의해 덮어쓰이고 애드온 업데이트 프로세스 중에 기본값으로 설정됩니다.

EKS에서 관리하는 필드는 manager가 EKS인 managedFields에 나열됩니다. EKS에서 관리하는 필드에는 service account, image, image url, liveness probe, readiness probe, labels, volumes, and volume mounts가 포함됩니다.

WARM_ENI_TARGET, WARM_IP_TARGET, MINIMUM_IP_TARGET 등 가장 자주 사용되는 필드는 관리되지 않으며 조정되지 않습니다. 이러한 필드의 변경 사항은 애드온을 업데이트할 때 보존됩니다.

프로덕션 클러스터를 업데이트하기 전에 특정 구성에 대해 비프로덕션 클러스터에서 애드온 동작을 테스트하는 것이 좋습니다. 또한 애드온 구성에 대한 EKS 사용자 가이드의 단계를 따르세요.

관리형 애드온으로 마이그레이션

버전 호환성을 관리하고 자체 관리형 VPC CNI의 보안 패치를 업데이트합니다. 자체 관리형 애드온을 업데이트하려면 Kubernetes API와 EKS 사용자 가이드 에 설명된 지침을 사용해야 합니다 . 기존 EKS 클러스터의 관리형 애드온으로 마이그레이션하는 것이 좋으며 마이그레이션 전에 현재 CNI 설정의 백업을 만드는 것이 좋습니다. 관리형 애드온을 구성하려면 Amazon EKS API, AWS Management Console 또는 AWS 명령줄 인터페이스를 활용할 수 있습니다.

kubectl apply view-last-applied daemonset aws-node -n kube-system > aws-k8s-cni-old.yaml

Amazon EKS는 필드가 기본 설정으로 관리되는 것으로 나열된 경우 CNI 구성 설정을 대체합니다. 관리되는 필드를 수정하지 않도록 주의하세요. 애드온은 환경 변수 및 CNI 모드와 같은 구성 필드를 조정하지 않습니다. 관리되는 CNI로 마이그레이션하는 동안 Pod와 애플리케이션은 계속 실행됩니다.

업데이트 전 CNI 설정 백업

VPC CNI는 고객 데이터 플레인(노드)에서 실행되므로 Amazon EKS는 새 버전이 출시되거나 클러스터를 새 Kubernetes 마이너 버전으로 업데이트 한 후에 애드온(관리형 및 자체 관리형)을 자동으로 업데이트하지 않습니다. 기존 클러스터의 애드온을 업데이트하려면 update-addon API를 통해 업데이트를 트리거하거나 EKS 콘솔에서 애드온에 대한 지금 업데이트 링크를 클릭해야 합니다. 자체 관리형 애드온을 배포한 경우 자체 관리형 VPC CNI 애드온 업데이트에서 언급한 단계를 따르세요.]

한 번에 하나의 마이너 버전을 업데이트하는 것을 강력히 권장합니다. 예를 들어, 현재 마이너 버전이 1.9이고 1.11로 업데이트하려는 경우 먼저 1.10의 최신 패치 버전으로 업데이트한 다음 1.11의 최신 패치 버전으로 업데이트 해야 합니다.

Amazon VPC CNI를 업데이트하기 전에 aws-node Daemonset을 검사합니다. 기존 설정을 백업합니다. 관리형 애드온을 사용하는 경우 Amazon EKS가 재정의할 수 있는 설정을 업데이트하지 않았는지 확인합니다. 자동화 워크플로에 업데이트 후 후크를 추가하거나 애드온 업데이트 후 수동 적용 단계를 권장합니다.

kubectl apply view-last-applied daemonset aws-node -n kube-system > aws-k8s-cni-old.yaml

자체 관리형 애드온의 경우 GitHub에서 releases 백업을 비교하여 사용 가능한 버전을 확인하고 업데이트하려는 버전의 변경 사항을 숙지하세요. Helm을 사용하여 자체 관리형 애드온을 관리하고 값 파일을 활용하여 설정을 적용하는 것이 좋습니다. Daemonset 삭제와 관련된 모든 업데이트 작업은 애플리케이션 다운타임을 초래하므로 피해야 합니다.

보안 컨텍스트 이해

VPC CNI를 효율적으로 관리하기 위해 구성된 보안 컨텍스트를 이해하는 것이 좋습니다. Amazon VPC CNI에는 CNI 바이너리와 ipamd(aws-node) Daemonset이라는 두 가지 구성 요소가 있습니다. CNI는 노드에서 바이너리로 실행되고 노드 루트 파일 시스템에 액세스할 수 있으며 노드 수준에서 iptables를 처리하기 때문에 특권 액세스도 있습니다. CNI 바이너리는 Pod가 추가되거나 제거될 때 kubelet에서 호출됩니다.

aws-node Daemonset은 노드 수준에서 IP 주소 관리를 담당하는 장기 실행 프로세스입니다. aws-node는 hostNetwork모드에서 실행되며 루프백 디바이스에 대한 액세스와 동일한 노드에 있는 다른 포드의 네트워크 활동을 허용합니다. aws-node init-container는 권한 모드에서 실행되며 CRI 소켓을 마운트하여 Daemonset이 노드에서 실행 중인 포드의 IP 사용을 모니터링할 수 있도록 합니다. Amazon EKS는 aws-node init 컨테이너의 권한 요구 사항을 제거하기 위해 노력하고 있습니다. 또한 aws-node는 NAT 항목을 업데이트하고 iptables 모듈을 로드해야 하므로 NET_ADMIN 권한으로 실행됩니다.

Amazon EKS는 Pod 및 네트워킹 설정에 대한 IP 관리를 위해 aws-node 매니페스트에서 정의한 대로 보안 정책을 배포할 것을 권장합니다. 최신 버전의 VPC CNI로 업데이트하는 것을 고려하세요. 또한 특별한 보안 요구 사항이 있는 경우 GitHub 이슈 여는 것을 고려하세요.

CNI에 대해 별도의 IAM 역할 사용

AWS VPC CNI에는 AWS Identity and Access Management(IAM) 권한이 필요합니다. IAM 역할을 사용하려면 CNI 정책을 설정해야 합니다. AmazonEKS_CNI_Policy 사용할 수 있습니다. IPv4 클러스터에 대한 AWS 관리 정책입니다. AmazonEKS CNI 관리 정책은 IPv4 클러스터에 대한 권한만 있습니다. 여기 나열된 권한이 있는 IPv6 클러스터에 대한 별도의 IAM 정책을 만들어야 합니다.

기본적으로 VPC CNI는 Amazon EKS 노드 IAM 역할 (관리형 노드 그룹과 자체 관리형 노드 그룹 모두)을 상속받습니다.

Amazon VPC CNI에 대한 관련 정책으로 별도의 IAM 역할을 구성하는 것이 강력히 권장됩니다. 그렇지 않은 경우 Amazon VPC CNI의 포드는 노드 IAM 역할에 할당된 권한을 얻고 노드에 할당된 인스턴스 프로필에 액세스할 수 있습니다.

VPC CNI 플러그인은 aws-node라는 서비스 계정을 만들고 구성합니다. 기본적으로 서비스 계정은 Amazon EKS CNI 정책이 첨부된 Amazon EKS 노드 IAM 역할에 바인딩됩니다. 별도의 IAM 역할을 사용하려면 Amazon EKS CNI 정책이 첨부된 새 서비스 계정을 만드는 것이 좋습니다 . 새 서비스 계정을 사용하려면 CNI 포드를 다시 배포 해야 합니다 . --service-account-role-arn새 클러스터를 만들 때 VPC CNI 관리형 애드온을 지정하는 것을 고려하세요. Amazon EKS 노드 역할에서 IPv4와 IPv6에 대한 Amazon EKS CNI 정책을 제거해야 합니다.

액세스 인스턴스 메타데이터를 차단하는 것이 좋습니다.보안 침해로 인한 폭발 반경을 최소화합니다.

Liveness/Readiness Probe 실패 처리

EKS 1.20 이상 클러스터의 라이브니스 및 준비 프로브 시간 초과 값(기본값 timeoutSeconds: 10)을 늘려 프로브 실패로 인해 애플리케이션의 Pod가 containerCreating 상태에 갇히는 것을 방지하는 것이 좋습니다. 이 문제는 데이터 집약적 및 일괄 처리 클러스터에서 확인되었습니다. CPU 사용량이 높으면 aws-node 프로브 상태 오류가 발생하여 Pod CPU 요청이 충족되지 않습니다. 프로브 시간 초과를 수정하는 것 외에도 aws-node의 CPU 리소스 요청(기본값 CPU: 25m)이 올바르게 구성되었는지 확인하세요. 노드에 문제가 없는 한 설정을 업데이트하지 않는 것이 좋습니다.

Amazon EKS 지원을 사용하는 동안 노드에서 sudo를 실행하는 것이 좋습니다 bash /opt/cni/bin/aws-cni-support.sh. 이 스크립트는 노드에서 kubelet 로그와 메모리 사용률을 평가하는 데 도움이 됩니다. 스크립트를 실행하려면 Amazon EKS 워커 노드에 SSM Agent를 설치하는 것을 고려하세요.

EKS 최적화 AMI 인스턴스가 아닌 인스턴스에서 IPTables 전달 정책 구성

사용자 지정 AMI를 사용하는 경우 kubelet.service 에서 iptables 전달 정책을 ACCEPT로 설정해야 합니다. 많은 시스템이 iptables 전달 정책을 DROP으로 설정합니다. HashiCorp Packer를 사용하여 사용자 지정 AMI를 빌드할 수 있습니다.AWS GitHub의 Amazon EKS AMI 리포지토리 에서 리소스와 구성 스크립트를 포함하는 빌드 사양. kubelet.service 를 업데이트할 수 있습니다.여기에 명시된 지침을 따르세요사용자 정의 AMI를 생성합니다.

CNI 버전을 정기적으로 업그레이드하세요

VPC CNI는 이전 버전과 호환됩니다. 최신 버전은 모든 Amazon EKS 지원 Kubernetes 버전과 호환됩니다. 또한 VPC CNI는 EKS 추가 기능으로 제공됩니다(위의 "VPC CNI 관리형 추가 기능 배포" 참조). EKS 추가 기능은 추가 기능의 업그레이드를 조정하지만 CNI와 같은 추가 기능은 데이터 플레인에서 실행되므로 자동으로 업그레이드하지 않습니다. 관리형 및 자체 관리형 작업자 노드 업그레이드 후 VPC CNI 추가 기능을 업그레이드해야 합니다.

2. EKS Cluster 생성

2.1 CloudFormation으로 배포

  • 가시다님이 OneClick으로 Mgmt와 EKS Cluster를 생성할 수 있는 CloudFormation yaml을 제공해 주셨습니다.
  • 기본 코드에서 비용절감을 위해 az 3개 대신 2개로 수정 하였습니다. CloudFormation 콘솔에서 배포진행합니다.
  • vpc 자동 생성
  • t3.medium 3노드 (1 mgmt, 2 eks worker) 생성됨
  • vpc cni가 aws-node Daemonset과 Pod 형태로 기동되었고 Pod IP는 public subnet 대역을 사용중입니다
  • t3.medium은 최대 3ENI, ENI당 6개 IP 할당가능합니다. (계산상 노드당 max pods는 17 입니다)

2.2 VPC CNI TEST

  • deployment로 busybox pod르 4대 생성, 정상적으로 public subnet pool에서 IP 할당됨
    • kubectl create deployment test --image=busybox --replicas=4 -- sleep infinity
  • Pod에 빠른 IP 할당을 위해 ENI가 추가되고, Secondary IP 또한 warm pool에 자동 추가되었네요
  • nginx pod 기동, IP로 접속 테스트결과 실패(?)
  • Pod에 별도 SG를 적용하지 않으면 노드의 SG적용을 받음, Mgmt에서 노드로 80 접속가능하도록 Port Open 후 정상 접속됨

3. IP 부족 이슈 문제점 & 해결

3.1 Node에 과도한 Pre-warm IP 할당으로 Subnet IP 고갈

  • 현상 :

    • 이벤트 대비하여 m5.4xlarge를 20 여대 이상 기동할려고 하였으나 중간에 Node Scane-out 실패 됨
    • failed to allocate a private IP/Prefix address: InsufficientCidrBlocks: There are not enough free cidr blocks in the specified subnet to satisfy the request
  • 원인 :

    • Pod IP가 할당되는 Subnet의 여유 IP가 고갈 됨
    • Node의 Networking 탭에서 확인한 결과 Private IPv4 ENI가 사용관계 없이 다수 생성되었고,
      Secondary private IPv4 address에 다수 IP가 기 할당되어 IP 부족을 유발 함
    • Warm pool이 확보하고 있는 IP가 실제 사용중인 IP로 카운트 됨
  • 조치1 : VPC CNI관련 환경변수(ENV) 수정하여 과도하게 IP 할당되지 않도록 조정

    • 파라미터 값 확인 : kubectl -n kube-system get ds aws-node -o yaml | egrep -A1 '(MINIMUM_IP_TARGET|WARM_IP_TARGET)'
      - WARM_PREFIX_TARGET : 현재 필요 수량을 초과하여 할당할 Prefix 수
      - WARM_IP_TARGET : 현재 필요 수량을 초과하여 할당할 IP 주소 수
      - MINIMUM_IP_TARGET : 언제든지 사용할 수 있는 최소 IP 주소 수
      - WARM_IP_TARGET 및 MINIMUM_IP_TARGET이 설정된 경우 WARM_PREFIX_TARGET를 오버라이드 합니다.
    • 파라미터 값 조절
      - kubectl set env ds aws-node -n kube-system MINIMUM_IP_TARGET=0 ## 최소 가용 IP 개수
      - kubectl set env ds aws-node -n kube-system WARM_IP_TARGET=1 ## warm pool 크기
      - 파라미터 조절 후 여유IP 1개를 남겨두고 미사용 IP들이 회수 됨
  • 조치2 : EKS Secondary CIDR 적용하여 100.64.x.x Subnet 생성 후 Pod IP로 할당처리

4. EKS Secondary CIDR

4.1 Amazon EKS, 추가적인 VPC CIDR 블록 지원

게시된 날짜: Oct 25, 2018

이제 Amazon Elastic Container Service for Kubernetes(EKS)를 사용하면 100.64.0.0/10 및 198.19.0.0/16 범위의 추가 IPv4 CIDR 블록으로 주소가 지정된 Amazon VPC에 클러스터를 생성할 수 있습니다. 따라서 고객은 EKS 클러스터에 대한 네트워킹을 유연하게 구성할 수 있습니다.

Amazon VPC에서 지원하는 CIDR 블록은 여기 IPv4 CIDR Block Association Restrictions라는 제목의 표에 나와 있습니다.

이전에는 EKS 고객이 RFC 1928 프라이빗 IP 주소 범위로 주소가 지정된 VPC에만 클러스터를 생성할 수 있었습니다. 즉, 고객은 EKS에서 관리하는 Kubernetes 팟 수를 지원하기에 충분한 프라이빗 IP 주소 공간을 할당할 수 없는 경우가 많았습니다.

이제 고객은 100.64.0.0/10 및 198.19.0.0/16 범위의 CIDR 블록으로 주소가 지정된 Amazon VPC에 EKS 클러스터를 생성할 수 있습니다. 이를 통해 고객은 Amazon EKS에서 관리하는 팟에 더 많은 IP 주소를 사용하고 네트워킹 아키텍처에 더 많은 유연성을 제공할 수 있습니다. 또한, CNI 사용자 지정 네트워킹 기능과 함께 100.64.0.0/10 및 198.19.0.0/16 범위의 보조 CIDR 블록을 VPC에 추가하면 팟이 VPC에서 더 이상 RFC 1918 IP 주소를 사용하지 않을 수 있습니다.

4.2 Secondar CIDR 적용

  • Shell Script : VPC명, Routing Table ID 수동 설정
# vim create-eks-secondary-cidr.sh

export VPC_ID=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=myeks-VPC --query 'Vpcs[].VpcId' --output text)
aws ec2 associate-vpc-cidr-block --vpc-id $VPC_ID --cidr-block 100.64.0.0/16

export AZ1=ap-northeast-2a
export AZ2=ap-northeast-2c

CUST_SNET1=$(aws ec2 create-subnet --cidr-block 100.64.0.0/19 --vpc-id $VPC_ID --availability-zone $AZ1 | jq -r .Subnet.SubnetId)
CUST_SNET2=$(aws ec2 create-subnet --cidr-block 100.64.32.0/19 --vpc-id $VPC_ID --availability-zone $AZ2 | jq -r .Subnet.SubnetId)

aws ec2 create-tags --resources $CUST_SNET1 --tags Key=Name,Value=myeks-eks-a-subnet
aws ec2 create-tags --resources $CUST_SNET2 --tags Key=Name,Value=myeks-eks-c-subnet

# aws ec2 create-tags --resources $CUST_SNET1 --tags Key=kubernetes.io/cluster/eksworkshop,Value=shared
# aws ec2 create-tags --resources $CUST_SNET2 --tags Key=kubernetes.io/cluster/eksworkshop,Value=shared

# aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC_ID |jq -r '.RouteTables[].RouteTableId'
export RTASSOC_ID=rtb-0269e8244af3da7e6

aws ec2 associate-route-table --route-table-id $RTASSOC_ID --subnet-id $CUST_SNET1
aws ec2 associate-route-table --route-table-id $RTASSOC_ID --subnet-id $CUST_SNET2

kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone
# kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=failure-domain.beta.kubernetes.io/zone

cat <<EOF  | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
 name: $AZ1
spec:
  subnet: $CUST_SNET1
EOF

cat <<EOF | kubectl apply -f -
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
 name: $AZ2
spec:
  subnet: $CUST_SNET2
EOF
  • Shell Script 실행

(devops@myeks:N/A) [root@myeks-bastion ~]# sh -x create-eks-secondary-cidr.sh 
++ aws ec2 describe-vpcs --filters Name=tag:Name,Values=myeks-VPC --query 'Vpcs[].VpcId' --output text
+ export VPC_ID=vpc-0b54860e41d918dae
+ VPC_ID=vpc-0b54860e41d918dae
+ aws ec2 associate-vpc-cidr-block --vpc-id vpc-0b54860e41d918dae --cidr-block 100.64.0.0/16
{
    "CidrBlockAssociation": {
        "AssociationId": "vpc-cidr-assoc-0bacfe22c3650f9c6",
        "CidrBlock": "100.64.0.0/16",
        "CidrBlockState": {
            "State": "associating"
        }
    },
    "VpcId": "vpc-0b54860e41d918dae"
}
+ export VPC_ID=vpc-0b54860e41d918dae
+ VPC_ID=vpc-0b54860e41d918dae
+ export AZ1=ap-northeast-2a
+ AZ1=ap-northeast-2a
+ export AZ2=ap-northeast-2c
+ AZ2=ap-northeast-2c
++ aws ec2 create-subnet --cidr-block 100.64.0.0/19 --vpc-id vpc-0b54860e41d918dae --availability-zone ap-northeast-2a
++ jq -r .Subnet.SubnetId
+ CUST_SNET1=subnet-0c77b2aa1a9874236
++ aws ec2 create-subnet --cidr-block 100.64.32.0/19 --vpc-id vpc-0b54860e41d918dae --availability-zone ap-northeast-2c
++ jq -r .Subnet.SubnetId
+ CUST_SNET2=subnet-0f4f977aa7eb55144
+ aws ec2 create-tags --resources subnet-0c77b2aa1a9874236 --tags Key=Name,Value=myeks-eks-a-subnet
+ aws ec2 create-tags --resources subnet-0f4f977aa7eb55144 --tags Key=Name,Value=myeks-eks-c-subnet
+ export RTASSOC_ID=rtb-0269e8244af3da7e6
+ RTASSOC_ID=rtb-0269e8244af3da7e6
+ aws ec2 associate-route-table --route-table-id rtb-0269e8244af3da7e6 --subnet-id subnet-0c77b2aa1a9874236
{
    "AssociationId": "rtbassoc-0a0a5625f0f43b97d",
    "AssociationState": {
        "State": "associated"
    }
}
+ aws ec2 associate-route-table --route-table-id rtb-0269e8244af3da7e6 --subnet-id subnet-0f4f977aa7eb55144
{
    "AssociationId": "rtbassoc-0d07aaf290e93f12d",
    "AssociationState": {
        "State": "associated"
    }
}
+ kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
daemonset.apps/aws-node env updated
+ kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone
daemonset.apps/aws-node env updated
+ kubectl apply -f -
+ cat
eniconfig.crd.k8s.amazonaws.com/ap-northeast-2a created
+ cat
+ kubectl apply -f -
eniconfig.crd.k8s.amazonaws.com/ap-northeast-2c created
  • Shell Script 실행 후 EC2 콘솔 또는 CLI로 노드 교체

  • Shell Sript 실행 결과

  • 서버 재기동 후, aws-node, kube-proxy를 제외하고 Secondary-CIDR 대역에서 IP가 할당 됨

5. 실습자원 삭제

  • CloudFormation에서 생성 역순으로 단계별 Stack 선택 후 자원을 삭제한다.

  • 일부 수동으로 추가된 내용은 확인 후 콘솔에서 수동으로 삭제한다.

6. 맺음말

Kubernetes Advanced Network Study 3기 9주차 과정이 매우 매운관계로 걱정을 많이 하였는데,
무사히 완주하게 되었다. 열정적으로 강의해 주신 가시다님과 함께 좋은 자료를 작성 & 공유해준 멤버들 통해서도 많은 도움을 받았다.
본 Study를 통해 내외적으로 많은 성장을 하게 되어 개인적으로도 매우 기쁘다.
다음과정 또한 기대된다. 수고했어. 화이팅!!!

profile
I'm SJ

5개의 댓글

comment-user-thumbnail
2024년 11월 2일

완주 수고 하셨습니다. 언제나 깔끔한 정리가 돋보입니다 ~ ^^/

답글 달기
comment-user-thumbnail
2024년 11월 6일

스터디 모임장 가시다입니다.

스터디 9주 기간 동안 인사이트 있는 내용 정리와 vagrant file 매번 작성해주셔서 감사드립니다.

조금 이르지만 올 한해 연말 마무리 잘 하시고, 그럼 내년에 또 다른 주제의 스터디에서 뵙겠습니다!

1개의 답글
comment-user-thumbnail
2024년 11월 8일

매주 Vagrant 실습 환경 구성해주신 덕에 AWS 비용 지불없이 스터디 진행할 수 있었습니다.
큰 도움주셔서 감사합니다~

1개의 답글