VPC CNI

개요

4.RESOURCE/KNOWLEDGE/AWS/AWS에서 EKS를 위해 제공하는 CNI이다.
aws 클라우드 환경에 최적화되어 있는 네트워크 플러그인이라고 보면 될 것 같다.
당연히 모니터링 등을 편하게 할 수 있도록 도와주고 추적이 잘 될 수 있게 해준다.

현업자들 왈 eks cni로는 이걸 쓰는 게 정답 수준이라고 한다.
기본적으로 트래픽 최적화를 어마무시하게 잘 해준다는 것.
이 이유를 본격적으로 탐구해보자.

특징

이 cni의 가장 큰 특징은 VPC의 ip 대역을 클러스터가 파드 ip 대역으로 그대로 사용한다는 것이다.
모든 파드는 vpc 대역의 ip를 할당받는다.
그리고 인스턴스의 eni가 해당 ip들을 담당해주게 된다.

그런데 eni는 스펙마다 최대로 받을 수 있는 ip 개수가 정해져 있다.
그래서 이를 초과하는 만큼 파드가 생성되는 경우에는 추가적인 eni가 붙게 된다.
그런데 인스턴스는 스펙마다 최대로 받을 수 있는 eni 개수도 정해져 있다!
그래서 사실.. 한 인스턴스에는 최대로 생성할 수 있는 파드의 개수가 제한된다..
물론 이걸 설정하는 방법이 존재하는데, 흔한 유즈 케이스까진 아니라고 하는 듯하다.
아래 [[#vpc 내 파드 제한 늘리기]]에서 다루겠다.

장점

얼핏 들으면 IP 대역을 빠르게 소모시키는 IP 먹는 하마 같지만(하마는 맞는 것 같다), 그만큼 가지는 이점이 있다.
파드 개수 제한은 꽤나 단점이 되는 것 같은데도 주로 사용되는 이유는 vpc 대역 ip를 받는 것으로 가지는 이점 때문이다.

단점

단점도 간단하게는 생각해봤는데, 결국 vpc의 ip를 활용하는데에서 마주칠 수 있는 어려움들이 있을 것이다.

대체로 뇌내 망상으로 생각해본 단점들이다.
아무튼 구축에 있어서 이런 사항이 있다는 것은 꼭 감안해야 할 것이다.

구조


구체적으로 vpc-cni라고 하면 두 가지 구성 요소가 포함된다.
image.png
그래서 이 친구는 컨테이너도 두 개다.

cni인 만큼 kube-system 네임스페이스에 데몬셋으로 관리되는 파드를 배포하여 관리한다.


두 요소는 서로 gRPC로 통신한다.[1]

tail -f /var/log/aws-routed-eni/ipamd.log

주소를 어떻게 관리하고 있는지 로그로 확인할 수 있다.
image.png
일단 현재 붙은 인터페이스를 추적하고 여기에 미리 선제적으로 ip들을 받아둔다.
image.png
그리고 파드가 생성될 때, 풀에 확보된 ip를 전달해준다.

설정 방법

image.png
콘솔에서 커스텀 세팅을 한 모습이다.
기본적으로 설정 파일에 대한 스키마를 보고 그것에 맞게 넣어주면 된다.

 aws eks describe-addon-configuration --addon-name vpc-cni --addon-version v1.15.1-eksbuild.1 | jq '.configurationSchema | fromjson'

이런 식으로 스키마를 볼 수 있고, 콘솔에서도 찾아볼 수 있다.
image.png
같은 세팅을 테라폼에서 한 모습이고, eksctl을 쓰던가 뭘 하던가 결국 다 json, 혹은 yaml형식의 파일로 만들면 된다.

vpc 내 파드 제한 늘리기

vpc cni의 특징 중 하나가 노드 당 파드 개수 제한이라고 했다.
이걸 조금 더 구체적으로 살펴보자.

기본 방식 - secondary ip

기본적으로, vpc cni는 eni에다가 파드 ip를 secondary로서 달아둔다.
그러나 이때 최대 개수가 지정돼 있다.

aws ec2 describe-instance-types \
    --filters "Name=instance-type,Values=c5.*" \
    --query "InstanceTypes[].{ \
        Type: InstanceType, \
        MaxENI: NetworkInfo.MaximumNetworkInterfaces, \
        IPv4addr: NetworkInfo.Ipv4AddressesPerInterface}" \
    --output table

이런 식으로 인스턴스 스펙 당 최대로 붙일 수 있는 eni개수와, 그 eni가 받을 수 있는 최대 ip 개수를 볼 수 있다.
image.png
그럼 내가 사용할 수 있는 ip는 총 몇 개일까?
맨 위 c5.4xlarge를 예로 들어보겠다.
일단 인스턴스에 eni가 부착되면 한 ip는 노드 자체에 대해 할당된다.
그렇기에 각 eni당 파드에 할당할 수 있는 ip 주소 개수는 30 - 1 인 29개이다.
그렇기에 해당 인스턴스에 배치할 수 있는 최대 파드는 29 * 8 인 232개가 된다.

hostNetwork를 사용하는 파드는!

클러스터 운영을 위해 기본으로 돌아가는, kube-proxy와 cni 파드가 hostNetwork로 돌아가고 있기에 한 노드당 최대 파드를 구하려면 사실 마지막에 2를 더해주어야 하는데, 어차피 이건 우리가 운영에 직접 사용할 파드도 아니라 제외한다.

kubectl describe node | grep Allocatable: -A6

클러스터의 정보로서도 파드의 개수가 표시되므로, 이렇게도 볼 수 있다.
image.png
현재 내 인스턴스는 t3.medium으로, 호스트 네트워크 파드까지 포함하여 17개까지 파드를 둘 수 있다고 나온다.

그럼 이러한 제약에서 자유로워질 수 있는 몇 가지 설정을 알아보자.

custom networking

먼저 이 방식은 인스턴스에 배치할 수 있는 파드 개수를 늘리는 것은 아니고, vpc내의 ip 대역을 늘리는 설정이라고 봐야한다.

이런 식으로, vpc 내에 완전히 새로운 서브넷을 지정해서 이 ip를 할당해주는 방법이 존재한다![2]
10.42 대역의 vpc에서 100.64 대역을 배치하는 괴상한 방식이 가능하다!
image.png
이 방법은 이렇게 vpc에 cidr block set을 설정하는 방식으로 이뤄진다.
vpc 자체가 일단 제공하는 기능을 활용하는 방식이 바로 커스텀 네트워킹이다.
image.png
vpc cidr 대역을 추가 할당했다면 거기에 상응하는 서브넷도 만들어준다.

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

vpc cni 쪽에서는 데몬셋 환경 설정을 통해 활성화할 수 있다.

apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
  # 가용영역 이름을 꼭 넣어야 하는 모양이더라. 나도 알고 싶지 않았다.
  name: ${SUBNET_AZ}
spec:
  # 허용하고자 하는 보안그룹 id
  securityGroups:
    - ${EKS_CLUSTER_SECURITY_GROUP_ID}
  # 만들어둔 서브넷 id
  subnet: ${SECONDARY_SUBNET_1}

여기에 ENIConfig라는 CRD를 만들어주면 설정 끝.
어떤 AZ에 어떤 추가 서브넷이 있는지 명시하는 방식이다.

만약 하나의 가용영역에 여러 개의 서브넷이 있는 상황이라면 당연히 이름 충돌이 발생한다.
image.png
이 경우에는, 이름은 알아서 만든 후에 각 노드 별로 k8s.amazonaws.com/eniConfig=EniConfigName 이런 식으로 어노테이션을 붙여줘야 한다.[3]
보다시피 라벨로도 달 수 있지만, 그냥 어노로 하자.
image.png
나는 직접적으로 하나를 넣어보았다.

kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone

이제 cni에서 해당 config 파일을 인식할 수 있도록 재동작을 시켜주면 된다.
image.png
이 다음에는? 해당 서브넷을 쓰는 새로운 노드 그룹을 만들면 된다!

Warning

다른 글들을 참고했는데, 내가 잘못 파악한 것 같다.
파드의 서브넷 대역을 따로 할당해준다는 것이 주골자라서, 노드 그룹을 추가로 만들 필요는 없는 듯하다.
여유가 생길 때 보완 정리하겠다.

간단하게 콘솔로만 진행했다.
image.png
파드를 해당 노드에 투입해봤다.
vpc의 ip가 부족하다면 이런 식으로 추가 대역을 넣어서 올리는 방법이 유용할 것이다.
다만, 이 경우 불필요하게 노드를 추가시켜야 할 수 있다는 단점이 있다.

prefix delegation

작은 일만 하는 파드들인데 이 제한으로 인해 노드를 여러 개 쓰는 것은 큰 비효율이다.
그래서 한 인스턴스에서 실행할 파드를 늘리기 위해 aws에서는 접두사 위임(prefix delegation)기능을 제공한다[4]

기존에 secondary ip들이, 전부 하나의 작은 서브넷처럼 작동한다.
원래 그냥 ip를 주던 것으로 끝내지 않고 활용할 수 있는 서브넷 대역을, 즉 접두사를 활용할 수 있게 준다고 하여 접두사 위임이라 부른다.
이렇게 하면 ..../28의 서브넷을 내부적으로 위임받아 파드에 할당할 수 있게 된다.
인스턴스가 받을 수 있는 각 ip들이 내부의 작은 서브넷이 되어 ip를 추가 할당할 수 있도록 해주는 것이다!

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

설정 자체는 이렇게 cni에 환경 설정을 넣는 것만으로 가능하다.
image.png
(그냥 보면 헷갈릴 수 있겠지만, 각 IP 대역은 4번째 옥텟의 상위 4비트가 전부 달라서 문제가 발생하지 않는다.)
4개의 비트이니 16개씩 각각 IP를 부여하는 게 가능해진다.
다만 한 eni에 대해 primary ip는 사용하지 못하므로, 전체 붙일 수 있는 (ip 개수 -1 ) * 16 개 만큼 할당할 수 있다고 보면 되겠다.

파드를 만들 때는 다음의 과정을 거친다고 한다.

image.png
위 사진에서도 보이듯이, 이게 설정되면 각 노드는 미리 접두사를 할당 받게 된다.
image.png
콘솔로 확인해보면 기존에 붙어있던 eni에 prefix delegation이 붙는 걸 볼 수 있다.
노드에 기본적으로 세팅할 수 있는 파드 개수의 최대값이 이미 지정되어 있기에 인스턴스를 재기동해야 할 수도 있다.
파드 최대 개수 설정이 재설정이 돼야 하기 때문이다.
이때 커스텀 런치 템플릿을 사용한 경우, 거기에서 파드 최대 개수를 명시적으로 바꿔줘야 한다.
image.png
런치 템플릿이 따로 없다면 재시작만 해도 알아서 최대 개수가 잘 지정되긴 한다.
image.png
이제 한 노드에 파드 폭격을 가해도 제대로 파드들이 여러 개 만들어진다!
image.png
재밌는 게, [[#custom networking]]과 함께 쓴다면 같은 az에 있는 다른 대역도 받을 수 있는 모양이다.
이 부분을 보고 내가 잘못 이해했음을 캐치했다.

모범 사례

보통 노드 당 생성 가능한 파드는 최대 110개로 설정돼있다.
물론 커스텀할 수 있긴 하다만, 그 정도까지 노드에 박아넣는 게 흔한 케이스는 아니니 참고.

그런데 궁금한 게, ECS 설명에서는 nitro 기반 인스턴스만이 이 설정이 가능하다고 나온다.[6]
image.png
aws에서는 대체로 nitro 하이퍼바이저를 지원하고 있어서 크게 상관할 필요가 없을지도 모른다.[7]
대체로 내가 사용하고 있는 t3도 nitro이니 신경을 쓸 필요는 없다.
다만 낮은 스펙의 인스턴스를 쓸 때는 충분히 주의해야 할 만한 사항으로 보인다.
이건 실험을 해봐야 알 것 같다.

https://docs.aws.amazon.com/ko_kr/eks/latest/best-practices/vpc-cni.html

관련 문서

이름 noteType created
VPC CNI knowledge 2025-02-11
2주차 - 네트워크 project 2025-02-25
2W - EKS VPC CNI 분석 published 2025-02-11

참고


  1. https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md ↩︎

  2. https://www.eksworkshop.com/docs/networking/vpc-cni/custom-networking/ ↩︎

  3. https://github.com/aws/amazon-vpc-cni-k8s ↩︎

  4. https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/cni-increase-ip-addresses.html ↩︎

  5. https://github.com/aws/aws-eks-best-practices/blob/master/content/networking/prefix-mode/index_windows.md#replace-all-nodes-during-migration-from-secondary-ip-mode-to-prefix-delegation-mode-or-vice-versa ↩︎

  6. https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/ec2-prefix-eni.html ↩︎

  7. https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/instance-types.html#instance-hypervisor-type ↩︎