在 Fargate 上安装和配置 Karpenter 以实现 Amazon EKS 的自动扩缩

通过减少操作来提高工作负载运行的效率和成本控制。
发布时间:2024 年 1 月 19 日
EKS 集群设置
EKS
Kubernetes
Fargate
教程
亚马逊云科技
Olawale Olaleye
亚马逊云科技使用经验
200 - 中级
完成所需时间
30 分钟
前提条件

注册 / 登录 亚马逊云科技账户

上次更新时间
2024 年 1 月 19 日

寻求按照最佳实践设计其 Kubernetes 集群的客户,力求最大化利用自动扩缩——这是亚马逊云科技良好架构框架中的一个重要概念。随着工作量的增加,以及计算容量需求的频繁变化,组织希望适应这些变化,但担心如何选择最优化的资源类型和大小以满足工作负载需求,并最终避免不必要的成本。

Karpenter 是一款开源的集群自动扩缩器,能自动为 Kubernetes 集群中无法调度的 Pod 提供新节点。使用 Karpenter,如果您希望基于操作系统或计算类型隔离节点,就不需要创建多个节点组来实现灵活性和多样性。例如,您可能有一个包含 GPU、CPU 和 Habana Gaudi 加速器实例类型的集群,若没有 Karpenter,您需要为每种实例类型创建专用节点组,并使用 nodeSelectors 来实现节点选择限制。

当您在 Kubernetes 集群中部署 Karpenter 时,它会安装 Karpenter 控制器和一个 webhook Pod,在控制器可用于扩展集群之前,此 webhook Pod 必须处于运行状态。这至少需要一个小型节点组,包含至少一个工作节点。作为一种替代方案,您可以通过为 karpenter 命名空间创建 Fargate 配置文件,在 EKS Fargate 上运行这些 Pod。这样做将导致部署到此命名空间的所有 Pod 在 EKS Fargate 上运行。

前提条件

开始本教程学习之前,您需要:

  • 安装最新版本的 kubectl。运行以下命令检查您的 kubectl 版本:kubectl version。
  • 安装最新版本的 eksctl。运行以下命令检查您的 eksctl 版本:eksctl info。
  • 安装最新版本的 Helm 命令行界面 (CLI)

概述

利用以下的 eksctl 集群模板,您将使用 Fargate 配置文件构建一个 Amazon EKS 集群,以提供我们在 karpenter 和 kube-system 命名空间中运行核心集群组件所需的计算能力。该模板包含以下组件:

  • Fargate 配置文件:Amazon Fargate 是一款适用于 EKS 的计算引擎。启用 Amazon Fargate 后,您无需配置、管理和扩缩您的 EC2 实例。Fargate 确保可用区扩展的同时,还帮您免去了复杂的 EC2 基础设施管理和实现跨可用区均衡 Replica Service 中的 Pod 负载的负杂工作。
  • 身份验证:服务账户 (IRSA) 映射所需的 IAM 角色,以便使 Kubernetes Pod 和亚马逊云科技服务之间可以进行通信。这包括负责在集群中提供所需的 EC2 计算能力的 Karpenter 控制器。此外,OpenID Connect (OIDC) 端点可实现无缝且安全的通信。
  • 身份映射:Amazon EKS 控制面板中 Karpenter IAM 主体所需的映射以及所需集群的基于角色的访问控制 (RBAC) 配置。
  • 部署示例应用程序:创建一个示例部署,以验证 Karpenter 随着 Pod 数量增加自动扩展所需的计算能力。

步骤 1:创建集群

在本节中,您将使用 CloudFormation 部署一项基础设施,用于支持 Karpenter 的核心功能。然后,您将继续创建此 cluster config 配置文件,定义 Fargate 配置文件的设置,以提供 Karpenter 和 CoreDNS 等核心集群所需的计算能力。

创建集群

1. 将以下内容复制粘贴到您的终端中,以定义您的环境变量参数。

export KARPENTER_NAMESPACE=kube-system
export KARPENTER_VERSION=v0.33.0
export K8S_VERSION=1.28
export AWS_PARTITION="aws" 
export CLUSTER_NAME="karpenter-fargate"
export AWS_DEFAULT_REGION="us-west-2"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export TEMPOUT=$(mktemp)

2. 将以下内容复制并粘贴到您的终端中,以使用 CloudFormation 设置 EKS 集群所需的基础设施。

curl -fsSL https://raw.githubusercontent.com/aws/karpenter-provider-aws/"${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 模板将部署的资源之间的相互关系,例如 SQS 队列、事件规则和 IAM 角色。现在,我们已做好创建 Amazon EKS 集群的准备。整个集群创建过程需要几分钟才能完成。如果您想要监控状态,请查看 Amazon CloudFormation 控制台,并在创建集群时更改区域(如果您正在不同的 Amazon 区域创建集群)。

3. 将以下内容复制并粘贴到您的终端中,以创建 Amazon EKS 集群。

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

iam:
 withOIDC: true
 serviceAccounts:
 - metadata:
 name: karpenter
 namespace: "${KARPENTER_NAMESPACE}"
 roleName: ${CLUSTER_NAME}-karpenter
 attachPolicyARNs:
 - arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:policy/KarpenterControllerPolicy-${CLUSTER_NAME}
 roleOnly: true

iamIdentityMappings:
- arn: "arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME}"
 username: system:node:{{EC2PrivateDNSName}}
 groups:
 - system:bootstrappers
 - system:nodes

fargateProfiles:
- name: karpenter
 selectors:
 - namespace: "${KARPENTER_NAMESPACE}"
EOF

4. 在您的终端中执行以下命令以验证集群创建成功:

export CLUSTER_ENDPOINT="$(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output text)"
export KARPENTER_IAM_ROLE_ARN="arn:${AWS_PARTITION}:iam::${AWS_ACCOUNT_ID}:role/${CLUSTER_NAME}-karpenter"
echo $CLUSTER_ENDPOINT $KARPENTER_IAM_ROLE_ARN

步骤 2:在集群上安装 Karpenter

成功创建集群后,我们现在可以在集群中安装 Karpenter。

1. 如果您已登录,请登出 Helm 注册表以对公共 ECR 执行未经身份验证的拉取。

helm registry logout public.ecr.aws 
docker logout public.ecr.aws

2. 然后使用以下命令安装 Karpenter:

helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter --version "${KARPENTER_VERSION}" --namespace "${KARPENTER_NAMESPACE}" --create-namespace \
 --set "serviceAccount.annotations.eks\.amazonaws\.com/role-arn=${KARPENTER_IAM_ROLE_ARN}" \
 --set "settings.clusterName=${CLUSTER_NAME}" \
 --set "settings.interruptionQueue=${CLUSTER_NAME}" \
 --set controller.resources.requests.cpu=1 \
 --set controller.resources.requests.memory=1Gi \
 --set controller.resources.limits.cpu=1 \
 --set controller.resources.limits.memory=1Gi \
 --wait

当上一个命令完成时,请使用以下命令验证 Karpenter Pod 和 CoreDNS(核心集群组件)处于 Running 状态,并由 Fargate 提供计算能力:

kubectl get pods -n kube-system -o wide

示例输出:

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-56666498f9-7j8zh 1/1 Running 0 16m 192.168.135.152 fargate-ip-192-168-135-152.us-west-2.compute.internal <none><none>
coredns-56666498f9-lj8q8 1/1 Running 0 16m 192.168.143.82 fargate-ip-192-168-143-82.us-west-2.compute.internal <none><none>
karpenter-c95c9f6fb-24r8c 1/1 Running 0 81s 192.168.167.246 fargate-ip-192-168-167-246.us-west-2.compute.internal <none><none>
karpenter-c95c9f6fb-fxvmv 1/1 Running 0 81s 192.168.117.84 fargate-ip-192-168-117-84.us-west-2.compute.internal <none><none>

上述输出显示,Karpenter 运行状况良好,可支持集群中将部署的工作负载所需的 EC2 计算能力。

步骤 3:创建默认节点池

安装 Karpenter 后,您需要设置默认的 NodePool。NodePool 的任务是对 Karpenter 可创建的节点以及在这些节点上可调度的 Pod 设置约束。

  1. 将以下内容复制并粘贴到您的终端中,为集群创建默认的配置程序:
cat <<EOF | envsubst | kubectl apply -f -
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
 name: default
spec:
 template:
 spec:
 requirements:
 - key: kubernetes.io/arch
 operator: In
 values: ["amd64"]
 - key: kubernetes.io/os
 operator: In
 values: ["linux"]
 - key: karpenter.sh/capacity-type
 operator: In
 values: ["spot"]
 - key: karpenter.k8s.aws/instance-category
 operator: In
 values: ["c", "m", "r"]
 - key: karpenter.k8s.aws/instance-generation
 operator: Gt
 values: ["2"]
 nodeClassRef:
 name: default
 limits:
 cpu: 1000
 disruption:
 consolidationPolicy: WhenUnderutilized
 expireAfter: 720h 
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
 name: default
spec:
 amiFamily: AL2 # Amazon Linux 2
 role: "KarpenterNodeRole-${CLUSTER_NAME}" 
 subnetSelectorTerms:
 - tags:
 karpenter.sh/discovery: "${CLUSTER_NAME}" 
 securityGroupSelectorTerms:
 - tags:
 karpenter.sh/discovery: "${CLUSTER_NAME}" 
EOF

此 NodePool 将会创建 EC2 Spot 实例,用于支持运行核心集群组件和 Karpenter Pod 的 kube-system 命名空间之外,其他命名空间中 Pod 的计算需求。

步骤 4:自动扩缩演示

1. 使用以下命令部署计数为 0 的示例应用程序:

kubectl create deployment app --image=public.ecr.aws/nginx/nginx:latest --replicas=0

2. 现在我们来看一下 Karpenter 如何自动扩缩并为 Pod 提供所需的 EC2 计算容量。打开第二个终端并运行以下命令来监控 Karpenter:

kubectl logs -f -n kube-system -l app.kubernetes.io/name=karpenter -c controller

3. 在上一个终端中运行以下命令来扩展工作负载,并在另一个终端中查看 Karpenter 控制器日志:

kubectl scale deployment app --replicas 5

4. 上一个命令将启动 5 个需要在一个或多个 EC2 工作节点上调度的 Pod。验证 Karpenter 是否已在 EC2 实例工作节点上启动了 Pod:

kubectl get pods -o wide

示例输出:

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app-6d954fd7d9-9ss7f 1/1 Running 0 6m5s 192.168.76.132 ip-192-168-73-43.us-west-2.compute.internal <none><none>
app-6d954fd7d9-bxbmh 1/1 Running 0 6m5s 192.168.86.102 ip-192-168-73-43.us-west-2.compute.internal <none><none>
app-6d954fd7d9-hsndg 1/1 Running 0 6m5s 192.168.86.252 ip-192-168-73-43.us-west-2.compute.internal <none><none>
app-6d954fd7d9-ljnzc 1/1 Running 0 6m5s 192.168.67.91 ip-192-168-73-43.us-west-2.compute.internal <none><none>
app-6d954fd7d9-q9x4d 1/1 Running 0 6m5s 192.168.89.34 ip-192-168-73-43.us-west-2.compute.internal <none><none>

清理资源

为避免持续产生费用,建议您删除在学习本教程的过程中创建的资源。删除示例部署:

kubectl delete deployment app

卸载 Karpenter:

helm uninstall karpenter --namespace kube-system

删除使用 CloudFormation 部署的基础设施

aws ec2 describe-launch-templates --filters Name=tag:karpenter.k8s.aws/cluster,Values=${CLUSTER_NAME} |
 jq -r ".LaunchTemplates[].LaunchTemplateName" |
 xargs -I{} aws ec2 delete-launch-template --launch-template-name {}

您可以使用以下命令删除 EKS 集群:

eksctl delete cluster --name "${CLUSTER_NAME}" 

删除成功后,输出结果应该如下所示:

2023-12-15 14:44:58 [ℹ] will delete stack "eksctl-karpenter-fargate-cluster"
2023-12-15 14:45:01 [✔] all cluster resources were deleted

总结

在本教程中,您成功搭建了一个 Amazon EKS 集群,并在 Fargate 上部署了 Karpenter,以便随着工作负载的增加,自动扩展集群所需的 EC2 计算能力。由于 Fargate 为 Karpenter Pod 提供计算能力,您无需管理该节点。Karpenter 负责管理 EKS 集群中其他节点的生命周期。