Kubernetes

EKS Node의 최대 Pod 수 - Security Groups per Pod 사용 시

백곰곰 2024. 11. 18. 22:34
728x90
반응형

개요

Security Groups per Pod 사용 시 EKS 노드에 설정되는 최대 pod 수가 달라지는 부분에 대해 설명합니다.


Security Groups Per Pod(sgpp)

해당 기능은 pod에서 노드의 sg를 사용하지 않고, pod 개별로 sg를 설정하여 사용할 수 있는 기능입니다.

VPC CNI에서 ENABLE_POD_ENI=true 설정을 추가하여 사용할 수 있습니다.

https://aws.github.io/aws-eks-best-practices/networking/sgpp/

ENABLE_POD_ENI=true 설정을 추가하면, 노드에는 하나의 Trunk ENI가 생성되고, pod가 생성될 때마다 Branch ENI가 생성되어 Trunk ENI와 연결됩니다.

Branch ENI에 pod의 sg가 설정됩니다. 참고로, Trunk ENI는 EC2에 추가할 수 있는 최대 ENI 수에 포함됩니다(참고). 그리고 Trunk ENI 수는 변하지 않습니다. 또한, sgpp에는 WARM pool 개념이 없습니다.

EC2 별로 최대 Branch ENI 수가 정해져 있으며, 해당 정보는 노드 Capacity의 vpc.amazonaws.com/pod-eni 항목에서 확인할 수 있습니다.

이는 노드에 배치할 수 있는 sgpp를 사용하는 최대 파드 수를 의미합니다.

Capacity:
  cpu:                        32
  ephemeral-storage:          104836076Ki
  hugepages-1Gi:              0
  hugepages-2Mi:              0
  hugepages-32Mi:             0
  hugepages-64Ki:             0
  memory:                     260790784Ki
  pods:                       234
  vpc.amazonaws.com/pod-eni:  54

sgpp를 사용하는 파드를 생성하면 아래와 같이 request/limit에 vpc.amazonaws.com/pod-eni: "1"가 추가됩니다.

    resources:
      limits:
        cpu: "1"
        memory: 500Mi
        vpc.amazonaws.com/pod-eni: "1"
      requests:
        cpu: "1"
        memory: 500Mi
        vpc.amazonaws.com/pod-eni: "1"

이를 통해, Branch ENI 수 이상으로 파드를 스케줄링할 수 없습니다.

EC2 타입 별 ENI 수와 Branch ENI 수는 링크에서 확인할 수 있습니다.

 

참고)


EKS Node의 최대 Pod 수(Security Groups per Pod 사용)

이전 글에서 확인한 내용과 같이, 기본적으로 노드에 스케줄링할 수 있는 최대 pod 수는 아래와 같이 계산할 수 있습니다.

예를 들어, m6i.xlarge 노드를 사용한다면, 4 * (15-1) +2 = 58 개의 파드를 스케줄링할 수 있습니다.

참고로, 여기서 노드에서 실제 사용 가능한 IP는 +2를 제외한 56개 입니다.

 

하지만, sgpp를 사용하면 기본적으로 노드에 Trunk ENI가 1개 생성되기 때문에, 위의 계산식을 사용하면 정확하지 않은 값이 설정됩니다.

이는 sgpp를 활성화해도 sgpp를 사용하는 파드와 아닌 파드가 모두 노드에 배치될 수 있기 때문입니다.

이때, Branch ENI는 sgpp를 사용하는 파드만 사용이 가능하기 때문에, 특정 노드에 sgpp를 사용하지 않는 파드만 배치된다면, 결국 하나의 ENI는 사용할 수 없게 됩니다.

따라서, 최대 파드 수 계산식에서 인스턴스 별 ENI의 수-1을 반영해야 노드에 배치된 모든 파드에 대한 IP를 할당을 보장할 수 있습니다.

(실제로는 Trunk ENI가 있기 때문에 sgpp를 사용하는 파드는 추가로 할당할 수 있지만, 최대 파드 수에서 sgpp를 사용하는 파드와 아닌 파드를 별도로 구분하여 계산하고 스케줄링 할 수는 없기 때문에, Branch ENI 수는 배제합니다.)

 

참고로 해당 내용이 최대 파드 수 계산에 반영되지 않는다면, 최대 파드 수와 사용 가능한 IP 수 간의 차이가 발생해서 파드는 스케줄링 되었지만 IP를 할당받지 못해 ContainerCreating 상태로 남게 됩니다. 아래는 실제 event와 로그입니다.

파드 event

  Warning  FailedCreatePodSandBox  2m24s (x1649 over 6h)  kubelet       (combined from similar events): Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "fd9a8fe8269e13548eabf10f155e7870e54b1a571ba5556b766136594f7f50ef": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to assign an IP address to container

VPC CNI 로그

{"level":"debug","ts":"2024-11-14T05:02:31.710Z","caller":"datastore/data_store.go:607","msg":"AssignPodIPv4Address: ENI eni-04670737609b3991f does not have available addresses"}
{"level":"debug","ts":"2024-11-14T05:02:33.687Z","caller":"datastore/data_store.go:607","msg":"AssignPodIPv4Address: IP address pool stats: total 203, assigned 203"}

EKS Node의 최대 Pod 수를 설정하는 방법

이제 최대 Pod수를 설정하는 방법을 확인해보겠습니다.

bootstrap.sh + max-pods-calculator.sh

EKS Optimized AMI를 사용하면, bootstrap.sh를 통해 최대 pod수가 지정됩니다.

하지만 이 과정에는 VPC CNI 옵션에 따라 최대 pod 수를 지정하는 옵션은 없기 때문에, 직접 쉘 스크립트를 수정하고 이를 반영해야 합니다.

bootstrap.sh

#calculate the max number of pods per instance type
MAX_PODS_FILE="/etc/eks/eni-max-pods.txt"
set +o pipefail
MAX_PODS=$(cat $MAX_PODS_FILE | awk "/^${INSTANCE_TYPE:-unset}/"' { print $2 }')
set -o pipefail
if [ -z "$MAX_PODS" ] || [ -z "$INSTANCE_TYPE" ]; then
  log "INFO: No entry for type '$INSTANCE_TYPE' in $MAX_PODS_FILE. Will attempt to auto-discover value."
  # When determining the value of maxPods, we're using the legacy calculation by default since it's more restrictive than
  # the PrefixDelegation based alternative and is likely to be in-use by more customers.
  # The legacy numbers also maintain backwards compatibility when used to calculate `kubeReserved.memory`
  MAX_PODS=$(/etc/eks/max-pods-calculator.sh --instance-type-from-imds --cni-version 1.10.0 --show-max-allowed)
fi
  • /etc/eks/eni-max-pods.txt 파일에 해당하는 EC2 타입이 없으면, max-pods-calculator.sh 실행
  • /etc/eks/eni-max-pods.txt 파일에는 기본 최대 pod 수 계산식의 결과가 기재되어 있음

여기서 sgpp 사용에 맞게 정확한 파드 수를 반영하려면, /etc/eks/eni-max-pods.txt 파일의 내용을 지우고 수정된 max-pods-calculator.sh를 실행하도록 설정이 필요합니다.

 

max-pods-calculator.sh

function print_help {
  echo "usage: $0 <instance(s)> [options]"
  echo "Calculates maxPods value to be used when starting up the kubelet."
  echo "-h,--help print this help."
  echo "--instance-type Specify the instance type to calculate max pods value."
  echo "--instance-type-from-imds Use this flag if the instance type should be fetched from IMDS."
  echo "--cni-version Specify the version of the CNI (example - 1.7.5)."
  echo "--cni-custom-networking-enabled Use this flag to indicate if CNI custom networking mode has been enabled."
  echo "--cni-prefix-delegation-enabled Use this flag to indicate if CNI prefix delegation has been enabled."
  echo "--cni-max-eni specify how many ENIs should be used for prefix delegation. Defaults to using all ENIs per instance."
  echo "--show-max-allowed Use this flag to show max number of Pods allowed to run in Worker Node. Otherwise the script will show the recommended value"
}
...
calculate_max_ip_addresses_secondary_ips() {
  enis=$1
  instance_max_eni_ips=$2
  echo $(($enis * ($instance_max_eni_ips - 1) + 2))
}

해당 스크립트에 ENABLE_POD_ENI 옵션을 추가하여 설정에 따라 calculate_max_ip_addresses_secondary_ips에서 참조하는 ENI 수를 변경해야 합니다.

 

karpenter - RESERVED_ENIS 옵션

karpenter를 사용하면 위의 내용처럼 스크립트를 수정하지 않아도 sgpp 사용을 고려하여 정확한 최대 pod 수를 반영할 수 있습니다.

아래와 같이 RESERVED_ENIS에 지정한 숫자만큼 제외하여 최대 pod 수가 계산됩니다.

ENILimitedPods

func ENILimitedPods(ctx context.Context, info ec2types.InstanceTypeInfo) *resource.Quantity {
    // The number of pods per node is calculated using the formula:
    // max number of ENIs * (IPv4 Addresses per ENI -1) + 2
    // https://github.com/awslabs/amazon-eks-ami/blob/main/templates/shared/runtime/eni-max-pods.txt
 
    // VPC CNI only uses the default network interface
    // https://github.com/aws/amazon-vpc-cni-k8s/blob/3294231c0dce52cfe473bf6c62f47956a3b333b6/scripts/gen_vpc_ip_limits.go#L162
    networkInterfaces := *info.NetworkInfo.NetworkCards[*info.NetworkInfo.DefaultNetworkCardIndex].MaximumNetworkInterfaces
    usableNetworkInterfaces := lo.Max([]int64{int64(int(networkInterfaces) - options.FromContext(ctx).ReservedENIs), 0})
    if usableNetworkInterfaces == 0 {
        return resource.NewQuantity(0, resource.DecimalSI)
    }
    addressesPerInterface := *info.NetworkInfo.Ipv4AddressesPerInterface
    return resources.Quantity(fmt.Sprint(usableNetworkInterfaces*(int64(addressesPerInterface)-1) + 2))
}

 

따라서, RESERVED_ENIS를 1로 설정하여 정확한 최대 pod 수를 반영할 수 있습니다.

728x90