Skip to content

Commit

Permalink
Adding utility to calculate max-pods for kubelet (awslabs#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
suket22 authored Jul 20, 2021
1 parent 62379e8 commit 2bea6dd
Showing 1 changed file with 151 additions and 0 deletions.
151 changes: 151 additions & 0 deletions files/max-pods-calculator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/bin/bash

set -o pipefail
set -o nounset
set -o errexit

err_report() {
echo "Exited with error on line $1"
}
trap 'err_report $LINENO' ERR

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."
}

POSITIONAL=()

while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-h|--help)
print_help
exit 1
;;
--instance-type)
INSTANCE_TYPE=$2
shift
shift
;;
--instance-type-from-imds)
INSTANCE_TYPE_FROM_IMDS=true
shift
;;
--cni-version)
CNI_VERSION=$2
shift
shift
;;
--cni-custom-networking-enabled)
CNI_CUSTOM_NETWORKING_ENABLED=true
shift
;;
--cni-prefix-delegation-enabled)
CNI_PREFIX_DELEGATION_ENABLED=true
shift
;;
--cni-max-eni)
CNI_MAX_ENI=$2
shift
shift
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done

CNI_VERSION="${CNI_VERSION:-}"
CNI_CUSTOM_NETWORKING_ENABLED="${CNI_CUSTOM_NETWORKING_ENABLED:-false}"
CNI_PREFIX_DELEGATION_ENABLED="${CNI_PREFIX_DELEGATION_ENABLED:-false}"
CNI_MAX_ENI="${CNI_MAX_ENI:-}"
INSTANCE_TYPE="${INSTANCE_TYPE:-}"
INSTANCE_TYPE_FROM_IMDS="${INSTANCE_TYPE_FROM_IMDS:-false}"

PREFIX_DELEGATION_SUPPORTED=false
IPS_PER_PREFIX=16

if [ "$INSTANCE_TYPE_FROM_IMDS" = true ]; then
TOKEN=$(curl -m 10 -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 600" -s "http://169.254.169.254/latest/api/token")
export AWS_DEFAULT_REGION=$(curl -s --retry 5 -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/dynamic/instance-identity/document | jq .region -r)
INSTANCE_TYPE=$(curl -m 10 -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-type)
elif [ -z "$INSTANCE_TYPE" ];
# There's no reasonable default for an instanceType so force one to be provided to the script.
then echo "You must specify an instance type to calculate max pods value."
exit 1
fi

if [ -z "$CNI_VERSION" ];
then echo "You must specify a CNI Version to use. Example - 1.7.5"
exit 1
fi

calculate_max_ip_addresses_prefix_delegation() {
enis=$1
instance_max_eni_ips=$2
echo $(($enis * (($instance_max_eni_ips - 1) * $IPS_PER_PREFIX ) + 2))
}

calculate_max_ip_addresses_secondary_ips() {
enis=$1
instance_max_eni_ips=$2
echo $(($enis * ($instance_max_eni_ips - 1) + 2))
}

min_number() {
printf "%s\n" "$@" | sort -g | head -n1
}


VERSION_SPLIT=(${CNI_VERSION//./ })
CNI_MAJOR_VERSION="${VERSION_SPLIT[0]}"
CNI_MINOR_VERSION="${VERSION_SPLIT[1]}"
if [[ "$CNI_MAJOR_VERSION" -gt 1 ]] || ([[ "$CNI_MAJOR_VERSION" = 1 ]] && [[ "$CNI_MINOR_VERSION" -gt 8 ]]); then
PREFIX_DELEGATION_SUPPORTED=true
fi

DESCRIBE_INSTANCES_RESULT=$(aws ec2 describe-instance-types --instance-type $INSTANCE_TYPE --query 'InstanceTypes[0].{Hypervisor: Hypervisor, EniCount: NetworkInfo.MaximumNetworkInterfaces, PodsPerEniCount: NetworkInfo.Ipv4AddressesPerInterface, CpuCount: VCpuInfo.DefaultVCpus'})

HYPERVISOR_TYPE=$(echo $DESCRIBE_INSTANCES_RESULT | jq -r '.Hypervisor' )
IS_NITRO=false
if [[ "$HYPERVISOR_TYPE" == "nitro" ]]; then
IS_NITRO=true
fi
INSTANCE_MAX_ENIS=$(echo $DESCRIBE_INSTANCES_RESULT | jq -r '.EniCount' )
INSTANCE_MAX_ENIS_IPS=$(echo $DESCRIBE_INSTANCES_RESULT | jq -r '.PodsPerEniCount' )

if [ -z "$CNI_MAX_ENI" ] ; then
enis_for_pods=$INSTANCE_MAX_ENIS
else
enis_for_pods="$(min_number $CNI_MAX_ENI $INSTANCE_MAX_ENIS)"
fi

if [ "$CNI_CUSTOM_NETWORKING_ENABLED" = true ] ; then
enis_for_pods=$((enis_for_pods-1))
fi


if [ "$IS_NITRO" = true ] && [ "$CNI_PREFIX_DELEGATION_ENABLED" = true ] && [ "$PREFIX_DELEGATION_SUPPORTED" = true ]; then
max_pods=$(calculate_max_ip_addresses_prefix_delegation $enis_for_pods $INSTANCE_MAX_ENIS_IPS)
else
max_pods=$(calculate_max_ip_addresses_secondary_ips $enis_for_pods $INSTANCE_MAX_ENIS_IPS)
fi

# Limit the total number of pods that can be launched on any instance type based on the vCPUs on that instance type.
MAX_POD_CEILING_FOR_LOW_CPU=110
MAX_POD_CEILING_FOR_HIGH_CPU=250
CPU_COUNT=$(echo $DESCRIBE_INSTANCES_RESULT | jq -r '.CpuCount' )
if [ "$CPU_COUNT" -gt 30 ] ; then
echo $(min_number $MAX_POD_CEILING_FOR_HIGH_CPU $max_pods)
else
echo $(min_number $MAX_POD_CEILING_FOR_LOW_CPU $max_pods)
fi

0 comments on commit 2bea6dd

Please sign in to comment.