2
头图

在亚马逊云科技 2021 re:Invent 大会期间,亚马逊云科技宣布为 Kubernetes 构建的开源自动扩缩容项目 Karpenter 升级至0.5版本并 GA ,可在生产环境使用。在 Kubernetes 上的 auto scaling 始终被人关注,当前的 kubernetes 提供 Cluster Autocaler 用于制定调度和扩缩决策。那么,既然有了Kubernetes Cluster Autoscaler,为何还要重复造轮子,去开发新的 auto scaling 工具呢?本文将介绍Karpenter作用和原理,同时对比一下大家熟悉的Cluster Autoscaler,并演示Karpenter的基本操作。

Karpenter是什么?

Karpenter 是一个为 Kubernetes 构建的开源自动扩缩容项目。它提高了 Kubernetes 应用程序的可用性,而无需手动或过度配置计算资源。Karpenter 旨在通过观察不可调度的 Pod 的聚合资源请求并做出启动和终止节点的决策,以最大限度地减少调度延迟,从而在几秒钟内(而不是几分钟)提供合适的计算资源来满足您的应用程序的需求。

Karpenter 与 Cluster Autocaler

在 Kubernetes 上可以实现集群自动缩放的工具,有 Cluster Autoscaler、Escalator 和 Cerebral 等。可惜有些工具已经疏于维护或终止开发。如今 Cluster Autoscaler 是集群自动缩放组件的首选,常见的优点包括:可以使集群根据需求的增长而自动扩容;通过有效整合利用资源和终止不必要的节点而较少基础架构带来的成本;其开发者是中立的,支持所有主流的公有云厂商;应用广泛,通过了实战的考验;支持大约1000个节点的集群。

下面我们了解一下 Cluster Autoscaler 是如何工作的,如下图所示:当有 Pod 因为资源不足状态为 pending 时,就会触发 Cluster Autoscaler 的扩展机制, Cluster Autoscaler 会增加托管节点组底层的 Auto Scaling Group 中的 desired 实例数量,从而通过 Auto Scaling Group 部署新的 Amazon EC2 实例加入节点组,作为预置新节点, pending 状态的 pod 会被调度到新的节点进行部署。

image.png

Cluster Autoscaler 在使用中有一些问题和注意事项。Cluster Autoscaler 对节点组进行的自动扩缩容,是依赖于 launch template 和 Auto Scaling group 进行的,所以 Auto Scaling group 的最大值和最小值也会限制节点组的最大和最小节点数量。有时 Cluster Autoscaler 为了进行一些指定的扩缩容操作,我们需要为每种实例类型或可用区单独区创建一个节点组。在节点组中如果创建节点失败,并不会立刻进行处理,因为 Cluster Autoscaler 处理错误的机制是基于超时。Cluster Autocaler 官方的性能测试报告,测试中使用了1000个节点,每个节点30个 pod ,超过这样的规模目前还没有官方的测试反馈。Cluster Autocaler 的操作也是比较复杂的,足有78个命令行参数。并且用户不能自定义调度器。基于以上的问题, Zalando 公司基于 Cluster Autocaler 做了修改,并且在 github 里 fork 出了一个分支,他们改进了节点处理代码,支持多实例类型的 Auto Scaling Group ,使用了更加可靠的 backoff 逻辑。但这些改进可能还不够,我们是否可以拥有一个更简单、扩展更快速、支持更大集群的扩缩容工具?这就是 Karpenter 了。

Karpenter 取消了节点组的概念,这是它与 Cluster Autoscaler 的根本区别,节点组通常是效率较低的原因之一。Karpenter 直接提供计算资源,动态的计算 pod 需要何种大小的 Amazon EC2 实例类型作为节点。从 Cluster Autocaler 的静态模版到 Karpenter 的动态生成模版,不必去创建节点组来确定实例的各种属性,从而降低了配置的复杂性。Cloud Provider 的 API 负载也会大大减少,在 Cluster Autocaler 中, Auto Scaling group 总会不断请求 Cloud Provider 来确认状态,在集群庞大以后,很可能碰到 API 调用限制,造成整个系统停止响应。而 Karpenter 只在创建和删除容量时调用 API ,这种设计可以支持更高的 API 吞吐量。没有了节点组,调度的复杂程度也被降低,因为 Cluster Autoscaler 不同节点组有不同属性,需要考虑 pod 被调度到哪个节点组。

image.png

下面我们了解一下 Karpenter 的工作过程,如下图所示:当有一个 pending 状态的 pod 时,如果还有存在的容量,则由 kube scheduler 进行调度。如果没有容量造成 pod 不能被调度,则由 Karpenter 绕过 kube scheduler 将 pod 绑定到新建的预置节点。

image.png

启动 Amazon EC2 实例的方式很多,Cluster Autoscaler使用 Auto Scaling group , Karpenter 使用 Amazon EC2 Fleets,这两种方式都可以启动 Amaozn EC2 实例。之所以选择 Amaozn EC2 Fleets,是因为它更强大更灵活,举例来说,当决定为一组 pod 创建节点时,可以不受限于可用区、实例类型,我们可以在 Cloud Providers 指定实例类型、可用区等属性,对 Karpenter 进行约束,Karpenter 可以在指定的属性中寻找最适合的实例类型来部署 pod 。Amazon EC2 fleet 也会选择指定实例中最便宜的实例类型。另外,使用 Auto Scaling group 来启动节点,大约需要30秒的时间,如果改用 Amazon EC2 Fleets 将远远少于30秒。

调度也非常重要, Karpenter 也优化了调度,一旦容量扩容的决定被做出,发出创建实例的请求,会立即获得实例 ID,不等实例创建完成就创建节点对象,将需要调度的 pod 绑定到节点。这是在 kube scheduler 之外强制执行了一个调度决策。这样做的好处有两个,第一,为 pod 部署降低了5秒左右的延迟,第二,不必匹配 Karpenter 与 kube scheduler 之间的版本。

通过 nodeSelector ,我们可以使用 kubernetes Well-Known Label :https://kubernetes.io/docs/re... 来指定属性启动实例,可以指定的属性包括可用区,实例类型,容量类型, CPU 架构,操作系统等。

如何为 pod 选择合适的 Amazon EC2 实例,即 Bin Packing 打包问题。Karpenter 采用了 First Fit Descending 算法,我们将 pod 按照从大到小排序,先将最大的 pod 去适配实例,如果不行就再换小一些的pod,这个过程尝试的实例越来越小,直到将最小的 pod 找到合适的实例。这样做的好处是,大的 pod 经常会在实例上留下一些间隙,可以让后面小 pod 填入,可以更有效的利用资源。对于pod排序的优先级,可以按照 CPU 、内存或 euclidean 。

Karpenter 不止增加节点,也负责终止节点。有一个控制器专门负责终止节点,默认一个节点5分钟内没有 pod ,Karpenter 就会终止它。另外,当 Amazon EC2 实例由于某种原因处于 unhealthy 状态或 spot 实例即将被回收,它都会发送一个事件,Karpenter 会响应这些事件,新创建节点来重部署上面的 pod 。另外 Karpenter 也可以为节点设置一个 TTL 值,比如配置节点生命周期是90天,这个功能在升级时非常有用,可以确保节点一直滚动升级。

Karpenter 也对节点的启动过程做了优化,之前节点启动都有一大堆步骤,一般云中的节点启动大约需要2分钟,实际这是由于过度配置造成的,现在这个延迟被 Karpenter 减少到了15到50秒。

Karpenter上手指南

Karpenter 自动配置新节点以响应不可调度的 pod。Karpenter 通过监控 Kubernetes 集群内的事件,然后向底层 cloud providers 发送命令来做到这一点。在此示例中,集群在亚马逊云科技的 Elastic Kubernetes Service (EKS) 上运行。Karpenter 旨在与云提供商无关,但目前仅支持亚马逊云科技 cloud providers 。欢迎加入https://github.com/awslabs/ka... 以开发其他版本 cloud providers 。完成本指南所需的时间不到 1 小时,成本低于 0.25 美元。记得按照文末方式对资源进行清理删除。 

Karpenter上手之环境准备

本次实验我们会用到四个工具:

1.亚马逊云科技 CLI ,可以参考以下链接进行安装:https://docs.aws.amazon.com/c... ,安装完成进行 AKSK 配置, region 输入 us-west-2 。

2.Kubectl ,参考以下链接安装:
https://kubernetes.io/docs/ta...

3.Eksctl ,参考以下链接安装:
https://docs.aws.amazon.com/e...

4.Helm ,参考以下链接安装:
https://helm.sh/docs/intro/in...

安装完必要工具后,运行 shell 设置以下环境变量:

export CLUSTER_NAME=$USER-karpenter-demo
export AWS_DEFAULT_REGION=us-west-2
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

*左滑查看更多

使用 eksctl 创建集群。此示例配置文件指定了一个具有一个初始节点的基本集群,并为该集群设置了一个 IAM OIDC provider,以用于后续步骤设置 IAM Roles for Service Accounts(IRSA) :

cat <<EOF > cluster.yaml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_DEFAULT_REGION}
  version: "1.20"
managedNodeGroups:
  - instanceType: m5.large
    amiFamily: AmazonLinux2
    name: ${CLUSTER_NAME}-ng
    desiredCapacity: 1
    minSize: 1
    maxSize: 10
iam:
  withOIDC: true
EOF
eksctl create cluster -f cluster.yaml

*左滑查看更多

实验中我们使用的是 Amazon EKS 里的 managed Node Groups 的节点来部署 Karpenter 。Karpenter 也可以运行在自建节点, fargate 。

Karpenter 发现子网需要有指定 tag:kubernetes.io/cluster/$CLUSTER_NAME  。将此 tag 添加到为您的集群配置的关联子网。

SUBNET_IDS=$(aws cloudformation describe-stacks \
    --stack-name eksctl-${CLUSTER_NAME}-cluster \
    --query 'Stacks[].Outputs[?OutputKey==`SubnetsPrivate`].OutputValue' \
    --output text)
aws ec2 create-tags \
    --resources $(echo $SUBNET_IDS | tr ',' '\n') \
    --tags Key="kubernetes.io/cluster/${CLUSTER_NAME}",Value=

*左滑查看更多

Karpenter 启动的 Amazon EC2 实例必须使用 InstanceProfile 运行,该配置文件授予运行容器和配置网络所需的权限。Karpenter 使用名称 KarpenterNodeRole-${ClusterName} 发现 InstanceProfile 。

首先,使用 Amazon CloudFormation 创建 IAM 资源。

TEMPOUT=$(mktemp)
curl -fsSL https://karpenter.sh/docs/getting-started/cloudformation.yaml > $TEMPOUT \
&& aws cloudformation deploy \
  --stack-name Karpenter-${CLUSTER_NAME} \
  --template-file ${TEMPOUT} \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides ClusterName=${CLUSTER_NAME}

*左滑查看更多

其次,使用配置文件授予 Amazon EC2 实例连接到集群的访问权限。此命令将 Karpenter 节点角色添加到您的 aws-auth 配置映射,允许具有此角色的节点连接到集群。

eksctl create iamidentitymapping \
  --username system:node:{{EC2PrivateDNSName}} \
  --cluster  ${CLUSTER_NAME} \
  --arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \
  --group system:bootstrappers \
  --group system:nodes

*左滑查看更多

Karpenter 本身还需要启动 Amazon EC2 实例的权限,与 Cluster Autoscaler 一样,我们通过 IAM Roles for Service Accounts(IRSA) 实现,用下面命令配置:

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

*左滑查看更多

如果您之前没有运行过 Amazon EC2 spot 实例,请运行下面命令,如果之前运行过 spot 实例,下面命令会报错,请忽略。

aws iam create-service-linked-role --aws-service-name spot.amazonaws.com

*左滑查看更多

Karpenter 是用 Helm 打包的,我们需要使用 Helm 来安装:

helm repo add karpenter https://charts.karpenter.sh
helm repo update
helm upgrade --install karpenter karpenter/karpenter --namespace karpenter \
  --create-namespace --set serviceAccount.create=false --version 0.4.1 \
  --wait # for the defaulting webhook to install before creating a Provisioner

*左滑查看更多

打开 debug 日志:

kubectl patch configmap config-logging -n karpenter --patch '{"data":{"loglevel.controller":"debug"}}'

*左滑查看更多

Karpenter 上手之 Provisioner 配置

Karpenter Provisioners 是一种 Kubernetes 自定义资源(CustomResourceDefinitions),使客户能够在其集群中配置 Karpenter 的约束,比如实例类型,可用区等。Karpenter Provisioner 带有一组全局默认值,如果您自己定义了Provisioner,默认值会被覆盖。一个集群中,也可以存在多个Karpenter Provisioners,默认情况下,pod 将使用名为 default 的 Provisioner 定义的规则。如果您创建了第二个Provisioner,请使用节点选择器指定 karpenter.sh/provisioner-name:alternative-provisioner。与此同时,使用默认 Provisioner 也需要使用节点选择器明确指定 karpenter.sh/provisioner-name 。

下面是一个 Provisioner 的示例:

cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  requirements:
    - key: node.k8s.aws/capacity-type
      operator: In
      values: ["spot"]
  provider:
    instanceProfile: KarpenterNodeInstanceProfile-${CLUSTER_NAME}
    cluster:
      name: ${CLUSTER_NAME}
      endpoint: $(aws eks describe-cluster --name ${CLUSTER_NAME} --query "cluster.endpoint" --output json)
  ttlSecondsAfterEmpty: 30
EOF

*左滑查看更多

可以看到,示例中仅对 capacity-type 做了 spot 的限制,并且指定了 ttlSecondsAfterEmpty为30 。使用这个 Provisioner 只会创建 spot 类型实例,并且在实例为空后30秒后关闭。更多 Provisioner 配置项可以参考:https://karpenter.sh/docs/pro...

Karpenter上手之自动扩缩容

我们使用 pause image 创建一个 replicas 为0的 deployment 。

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
          resources:
            requests:
              cpu: 1
EOF

*左滑查看更多

然后将 replicas 设置为5,观察 karpenter 日志:

kubectl scale deployment inflate --replicas 5
kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)

*左滑查看更多

根据下面输出的 karpenter 日志我们可以看出,16:13:32时, karpenter 发现5个 pod 被创建。我们看到在16:13:37时,完成了节点启动以及 pod 与节点绑定的操作,整个过程仅用了5秒。我们看到,这次 pod 调度需要5个 vcpu ,karpenter 自动选择了 c5.2xlagre 的示例,这体现了 karpenter 减少复杂度,追求速度的设计理念,会把多个 pod 调度合并在一个节点上。

2021-10-31T16:13:30.536Z        INFO    controller.allocation.provisioner/default       Starting provisioning loop      {"commit": "c902206"}
2021-10-31T16:13:30.536Z        INFO    controller.allocation.provisioner/default       Waiting to batch additional pods        {"commit": "c902206"}
2021-10-31T16:13:32.050Z        INFO    controller.allocation.provisioner/default       Found 5 provisionable pods      {"commit": "c902206"}
2021-10-31T16:13:32.932Z        DEBUG   controller.allocation.provisioner/default       Discovered 318 EC2 instance types       {"commit": "c902206"}
2021-10-31T16:13:32.933Z        DEBUG   controller.allocation.provisioner/default       Excluding instance type t4g.nano because there are not enough resources for kubelet and system overhead     {"commit": "c902206"}
2021-10-31T16:13:32.935Z        DEBUG   controller.allocation.provisioner/default       Excluding instance type t3.nano because there are not enough resources for kubelet and system overhead      {"commit": "c902206"}
2021-10-31T16:13:32.939Z        DEBUG   controller.allocation.provisioner/default       Excluding instance type t3a.nano because there are not enough resources for kubelet and system overhead     {"commit": "c902206"}
2021-10-31T16:13:32.968Z        INFO    controller.allocation.provisioner/default       Computed packing for 5 pod(s) with instance type option(s) [c1.xlarge c3.2xlarge c4.2xlarge c6i.2xlarge c5a.2xlarge c5d.2xlarge c6g.2xlarge c5ad.2xlarge c6gd.2xlarge a1.2xlarge c6gn.2xlarge c5.2xlarge c5n.2xlarge m3.2xlarge m6g.2xlarge m4.2xlarge m5zn.2xlarge m5dn.2xlarge m5n.2xlarge m5d.2xlarge]       {"commit": "c902206"}
2021-10-31T16:13:33.146Z        DEBUG   controller.allocation.provisioner/default       Discovered subnets: [subnet-0a538ed8c05288206 subnet-07a9d3f4dbc92164c subnet-0b14f140baa9a38cb]    {"commit": "c902206"}
2021-10-31T16:13:33.262Z        DEBUG   controller.allocation.provisioner/default       Discovered security groups: [sg-0afb56113d9feb2e8]      {"commit": "c902206"}
2021-10-31T16:13:33.265Z        DEBUG   controller.allocation.provisioner/default       Discovered kubernetes version 1.20      {"commit": "c902206"}
2021-10-31T16:13:33.317Z        DEBUG   controller.allocation.provisioner/default       Discovered ami ami-0a69abe3cea2499b7 for query /aws/service/eks/optimized-ami/1.20/amazon-linux-2-arm64/recommended/image_id        {"commit": "c902206"}
2021-10-31T16:13:33.365Z        DEBUG   controller.allocation.provisioner/default       Discovered ami ami-088105bab8bfa2db6 for query /aws/service/eks/optimized-ami/1.20/amazon-linux-2/recommended/image_id      {"commit": "c902206"}
2021-10-31T16:13:33.365Z        DEBUG   controller.allocation.provisioner/default       Discovered caBundle, length 1066        {"commit": "c902206"}
2021-10-31T16:13:33.506Z        DEBUG   controller.allocation.provisioner/default       Created launch template, Karpenter-karpenter-demo-16982985708254790476      {"commit": "c902206"}
2021-10-31T16:13:33.507Z        DEBUG   controller.allocation.provisioner/default       Discovered caBundle, length 1066        {"commit": "c902206"}
2021-10-31T16:13:33.640Z        DEBUG   controller.allocation.provisioner/default       Created launch template, Karpenter-karpenter-demo-11290710479729449633      {"commit": "c902206"}
2021-10-31T16:13:36.898Z        INFO    controller.allocation.provisioner/default       Launched instance: i-0f38cb0ade09a537c, hostname: ip-192-168-132-54.us-west-2.compute.internal, type: c5.2xlarge, zone: us-west-2a, capacityType: spot      {"commit": "c902206"}
2021-10-31T16:13:37.050Z        INFO    controller.allocation.provisioner/default       Bound 5 pod(s) to node ip-192-168-132-54.us-west-2.compute.internal{"commit": "c902206"}
2021-10-31T16:13:37.050Z        INFO    controller.allocation.provisioner/default       Starting provisioning loop      {"commit": "c902206"}
2021-10-31T16:13:37.050Z        INFO    controller.allocation.provisioner/default       Waiting to batch additional pods        {"commit": "c902206"}
2021-10-31T16:13:38.050Z        INFO    controller.allocation.provisioner/default       Found 0 provisionable pods      {"commit": "c902206"}

*左滑查看更多

我们选择一个 pod 来查看它的创建耗时:

kubectl get pod <pod_name> -oyaml

*左滑查看更多

从下面日志可以看出,16:13:36时, pod 被调度,16:14:45时 pod ready 。整个过程为1分9秒。考虑到是5个 pod ,并且这段时间是创建 ec2 启动模版,ec2 实例启动并加入集群节点和 pod 向节点部署的时间,整个过程还是很快的。如果想加速这段过程,可以考虑使用 placeholder pod 做 Over-Provisioning 的方式。

……
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2021-10-31T16:14:17Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2021-10-31T16:14:45Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2021-10-31T16:14:45Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2021-10-31T16:13:36Z"
    status: "True"
type: PodScheduled
……

*左滑查看更多

我们打开 Amazon EC2 Dashboard,查看 spot requests,可以看到 karpenter 是使用的 spot fleet,当前我们使用的是 spot 实例,如果使用 karpenter 启动 on demand 实例,可以使用 aws cli 命令 aws ec2 describe-fleets 去查看。

image.png

下面我们删除刚才创建的 Deployment,并观察 karpenter 日志:

kubectl delete deployment inflate
kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)

*左滑查看更多

从日志中我们可以看到,16:40:16时发现了空实例,ttlSecondsAfterEmpty 在Provisioner 中设置为30,则30秒后,才将实例终止。

2021-10-31T16:13:39.549Z        INFO    controller.allocation.provisioner/default       Watching for pod events {"commit": "c902206"}
2021-10-31T16:40:16.040Z        INFO    controller.Node Added TTL to empty node ip-192-168-132-54.us-west-2.compute.internal    {"commit": "c902206"}
2021-10-31T16:40:46.059Z        INFO    controller.Node Triggering termination after 30s for empty node ip-192-168-132-54.us-west-2.compute.internal    {"commit": "c902206"}
2021-10-31T16:40:46.103Z        INFO    controller.Termination  Cordoned node ip-192-168-132-54.us-west-2.compute.internal      {"commit": "c902206"}
2021-10-31T16:40:46.290Z        INFO    controller.Termination  Deleted node ip-192-168-132-54.us-west-2.compute.internal       {"commit": "c902206"}

*左滑查看更多

除了利用 provisioner 去自动选择扩展节点类型,我们也可以在 pod 中使用 nodeSelector 来指定 Well-Known Labes 启动节点,下面是一段 Deployment 示例:

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
          resources:
            requests:
              cpu: 1
      nodeSelector:
        node.kubernetes.io/instance-type: c5.xlarge
EOF

*左滑查看更多

观察 karpenter 日志,本次已经有了第一次扩展创建的 launch template ,所以从发现 pod provisionable ,到创建实例绑定 pod ,仅用了4秒。但与第一次不同,我们这次在 Deployment 时利用 nodeSelector 指定了使用 c5.xlarge 实例,所以 karpenter 创建了2台 c5.xlarge 实例来部署 pod,而不是第一次的一台 c5.2xlarge。

kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
……
2021-10-31T17:13:28.459Z        INFO    controller.allocation.provisioner/default       Waiting to batch additional pods        {"commit": "c902206"}
2021-10-31T17:13:29.549Z        INFO    controller.allocation.provisioner/default       Found 5 provisionable pods      {"commit": "c902206"}
2021-10-31T17:13:30.648Z        DEBUG   controller.allocation.provisioner/default       Discovered 318 EC2 instance types       {"commit": "c902206"}
2021-10-31T17:13:30.661Z        INFO    controller.allocation.provisioner/default       Computed packing for 3 pod(s) with instance type option(s) [c5.xlarge]      {"commit": "c902206"}
2021-10-31T17:13:30.675Z        INFO    controller.allocation.provisioner/default       Incremented node count to 2 on packing for 2 pod(s) with instance type option(s) [c5.xlarge]        {"commit": "c902206"}
2021-10-31T17:13:30.860Z        DEBUG   controller.allocation.provisioner/default       Discovered subnets: [subnet-0a538ed8c05288206 subnet-07a9d3f4dbc92164c subnet-0b14f140baa9a38cb]    {"commit": "c902206"}
2021-10-31T17:13:30.951Z        DEBUG   controller.allocation.provisioner/default       Discovered security groups: [sg-0afb56113d9feb2e8]      {"commit": "c902206"}
2021-10-31T17:13:30.955Z        DEBUG   controller.allocation.provisioner/default       Discovered kubernetes version 1.20      {"commit": "c902206"}
2021-10-31T17:13:31.016Z        DEBUG   controller.allocation.provisioner/default       Discovered ami ami-088105bab8bfa2db6 for query /aws/service/eks/optimized-ami/1.20/amazon-linux-2/recommended/image_id      {"commit": "c902206"}
2021-10-31T17:13:31.016Z        DEBUG   controller.allocation.provisioner/default       Discovered caBundle, length 1066        {"commit": "c902206"}
2021-10-31T17:13:31.052Z        DEBUG   controller.allocation.provisioner/default       Discovered launch template Karpenter-karpenter-demo-11290710479729449633    {"commit": "c902206"}
2021-10-31T17:13:33.150Z        INFO    controller.allocation.provisioner/default       Launched instance: i-04604513375c3dc3a, hostname: ip-192-168-156-86.us-west-2.compute.internal, type: c5.xlarge, zone: us-west-2a, capacityType: spot       {"commit": "c902206"}
2021-10-31T17:13:33.150Z        INFO    controller.allocation.provisioner/default       Launched instance: i-0e058845370c428ec, hostname: ip-192-168-154-221.us-west-2.compute.internal, type: c5.xlarge, zone: us-west-2a, capacityType: spot      {"commit": "c902206"}
2021-10-31T17:13:33.207Z        INFO    controller.allocation.provisioner/default       Bound 3 pod(s) to node ip-192-168-156-86.us-west-2.compute.internal{"commit": "c902206"}
2021-10-31T17:13:33.233Z        INFO    controller.allocation.provisioner/default       Bound 2 pod(s) to node ip-192-168-154-221.us-west-2.compute.internal{"commit": "c902206"}
……

*左滑查看更多

打开 Amazon EC2 Dashboard,查看 spot request,可以看到2个 spot fleet,可以看到即使同型号实例,karpenter 为了可以快速调度,也会分别创建 fleet。

image.png

删除实验环境

执行下面命令,删除实验环境,避免产生额外费用。

helm uninstall karpenter --namespace karpenter
eksctl delete iamserviceaccount --cluster ${CLUSTER_NAME} --name karpenter --namespace karpenter
aws cloudformation delete-stack --stack-name Karpenter-${CLUSTER_NAME}
aws ec2 describe-launch-templates \
    | jq -r ".LaunchTemplates[].LaunchTemplateName" \
    | grep -i Karpenter-${CLUSTER_NAME} \
    | xargs -I{} aws ec2 delete-launch-template --launch-template-name {}
eksctl delete cluster --name ${CLUSTER_NAME}

*左滑查看更多

总结

Karpenter 作为一款新的 Kubernetes auto scaling 工具,它有着更快速更灵活的优势。对于大规模的 Kubernetes 集群有着更好的支持。在具备这些优点的同时,它还大大降低的运维工作量,使 auto scaling 更加自动。

本篇作者

image.png

夏焱

亚马逊云科技解决方案架构师

目前专注于容器化解决方案。在加入亚马逊云科技之前,曾就职于惠普、IBM 等科技公司,从事数据中心基础架构相关工作,拥有十余年技术服务经验。


亚马逊云开发者
2.9k 声望9.6k 粉丝

亚马逊云开发者社区是面向开发者交流与互动的平台。在这里,你可以分享和获取有关云计算、人工智能、IoT、区块链等相关技术和前沿知识,也可以与同行或爱好者们交流探讨,共同成长。