在亚马逊云科技 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 会被调度到新的节点进行部署。
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 被调度到哪个节点组。
下面我们了解一下 Karpenter 的工作过程,如下图所示:当有一个 pending 状态的 pod 时,如果还有存在的容量,则由 kube scheduler 进行调度。如果没有容量造成 pod 不能被调度,则由 Karpenter 绕过 kube scheduler 将 pod 绑定到新建的预置节点。
启动 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/reference/labels-annotations-taints/ 来指定属性启动实例,可以指定的属性包括可用区,实例类型,容量类型, 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/karpenter 以开发其他版本 cloud providers 。完成本指南所需的时间不到 1 小时,成本低于 0.25 美元。记得按照文末方式对资源进行清理删除。
Karpenter 上手之环境准备
本次实验我们会用到四个工具:
1.亚马逊云科技 CLI ,可以参考以下链接进行安装:https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html ,安装完成进行 AKSK 配置, region 输入 us-west-2 。
2.Kubectl ,参考以下链接安装:
https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/
3.Eksctl ,参考以下链接安装:
https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html
4.Helm ,参考以下链接安装:
https://helm.sh/docs/intro/install/
安装完必要工具后,运行 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/provisioner-crd/
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 去查看。
下面我们删除刚才创建的 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。
删除实验环境
执行下面命令,删除实验环境,避免产生额外费用。
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 更加自动。
本篇作者
夏焱
亚马逊云科技解决方案架构师
目前专注于容器化解决方案。在加入亚马逊云科技之前,曾就职于惠普、IBM 等科技公司,从事数据中心基础架构相关工作,拥有十余年技术服务经验。
评论