环境准备

在安装Karpenter之前,需要完成以下工作:

  • 创建好一个EKS集群

  • 创建Karpenter需要使用到的Policy及service account等资源。


创建EKS集群(可选)

配置环境变量:

export CLUSTER_NAME=$(eksctl get clusters -o json | jq -r '.[0].Name')
export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)"
export AZ1="$AWS_REGION"a
export AZ2="$AWS_REGION"b

echo Cluster Name:$CLUSTER_NAME AWS Region:$AWS_REGION Account ID:$AWS_ACCOUNT_ID Cluster Endpoint:$CLUSTER_ENDPOINT AZ1:$AZ1 AZ2:$AZ2

如果手头已经有EKS集群,可以跳过本部分;如果没有,用eksctl快速创建一个出来:

eksctl create cluster -f - <<EOF
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_REGION}
  version: "1.27"
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}

managedNodeGroups:
- instanceType: m5.large
  amiFamily: AmazonLinux2
  name: ${CLUSTER_NAME}-ng
  desiredCapacity: 2
  minSize: 1
  maxSize: 10

EOF

创建Karpenter需要用的到Policy及Service account

先将EKS集群名称、帐号id等信息保存到环境变量:

export CLUSTER_NAME=${eks_cluster_name}
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)"

由Karpenter创建出来的EC2实例也需要绑定一个Role,在这里我们创建 KarpenterNodeRole-${ClusterName}这个InstanceProfile,来为实例授予访问ECR, 创建容器、配置ENI等相关权限:

TEMPOUT=$(mktemp)

export KARPENTER_VERSION=v0.31.1

curl -fsSL https://raw.githubusercontent.com/aws/karpenter/"${KARPENTER_VERSION}"/website/content/en/preview/getting-started/getting-started-with-karpenter/cloudformation.yaml  > $TEMPOUT \
&& aws cloudformation deploy \
  --stack-name Karpenter-${CLUSTER_NAME} \
  --template-file ${TEMPOUT} \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides ClusterName=${CLUSTER_NAME}

这个CloudFormation创建出来的资源如下,包括一个KarpenterControllerPolicy(绑在Karpenter Pod上)和一个NodeRole(绑在Karpenter创建出来的节点上),KarpenterControllerPolicy后面我们会用到:

image-20231026211821237

将NodeRole添加到aws-auth configmap里

将Karpenter创建出来的节点(上面绑定着KarpenterNodeRole-xxx),让它可以连接到EKS集群(如执行kubectl命令):

eksctl create iamidentitymapping \
  --username system:node:{{EC2PrivateDNSName}} \
  --cluster  ${CLUSTER_NAME} \
  --arn arn:aws:iam::${ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \
  --group system:bootstrappers \
  --group system:nodes
  
# You can verify the entry is now in the AWS auth map by running the following command.  
kubectl describe configmap -n kube-system aws-auth

image-20231026065454438

创建KarpenterController的IAM Role

由于Karpenter POD需要有创建实例的权限,这里使用IRSA机制——创建一个service account,用于给后面的karpenter pod绑定:

eksctl utils associate-iam-oidc-provider --cluster ${CLUSTER_NAME} --approve

eksctl create iamserviceaccount \
  --cluster "${CLUSTER_NAME}" --name karpenter --namespace karpenter \
  --role-name "${CLUSTER_NAME}-karpenter" \
  --attach-policy-arn "arn:aws:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME}" \
  --role-only \
  --approve

export KARPENTER_IAM_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/${CLUSTER_NAME}-karpenter"

从IAM控制台看到,这个KarpenterControllerPolicy具有创建EC2 Fleet等权限:

image-20220530100807804

这一步将花费大概两分钟,创建完成后,可以执行以下命令来检查创建的service account:

$ kubectl get serviceaccounts --namespace karpenter
NAME        SECRETS   AGE
default     0         73s
karpenter   0         73s