Karpenter现在已经部署完毕,我们来探索它是如何管理node的生命周期
运行以下命令,创建一个deployement:
cat <<EOF > inflate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 0
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
nodeSelector:
intent: apps
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
requests:
cpu: 1
memory: 1.5Gi
EOF
kubectl apply -f inflate.yaml
intent: apps
,当前集群上的节点没有提前设置对应的label,所以只要有新的pod拉起都不会部署到当前集群的节点上,迫使Karpenter创建新的node来满足对应的条件。在进行后面的操作之前,建议先安装kube-ops-view
,参考 https://www.eksworkshop.com/beginner/080_scaling/install_kube_ops_view/
。当然也可使用纯kubectl命令来观察node/pod
等状态的变化
运行以下命令,将replica数量设置为1:
kubectl scale deployment inflate --replicas 1
在这个过程中,观察karpenter-controller
的日志变化:
kubectl logs -f deployment/karpenter-controller -n karpenter
由于新创建的pod,当前没有node能满足它的selector条件,所以被标记为unschedulable。Karpenter会创建新的node来满足它的条件:
从日志中注意到,karpenter从以下机型进行了挑选:
[c5ad.large c5a.large c5.large c6a.large c3.large c5d.large t3a.medium c6i.large c4.large c6id.large t3.medium c5n.large m4.large m5d.large m5ad.large t3a.large m5zn.large m5.large m1.large m5a.large]
上面所有的机型都满足pod所需的CPU/内存资源,且为最小配置,以减少资源的浪费——在这个过程中Karpenter使用了 First Fit Decreasing (FFD) 算法。
Karpenter使用Instant mode EC2 Fleet
( https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instant-fleet.html
)来创建机器:
EC2 Fleet instant mode
使用同步调用
来创建机器;而Cluster Autoscaler
使用异步调用
的方式来创建机器。EC2 Fleet in instant mode
使用 capacity-optimized-prioritized
方式创建机器,这种方式会从spot容量池中挑选数量最多的机型,减少spot实例被回收的机率。参考 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-allocation-strategy.html
所以,使用Karpenter,无需再提前定义多个ASG配置,减少了运维的繁琐。
执行kubectl命令,来确认replica数量达到目标值:
$ kubectl get deployment inflate
NAME READY UP-TO-DATE AVAILABLE AGE
inflate 1/1 1 1 1m
查看新创建的机器:
intent=apps
karpenter.sh/provisioner-name
为 default
,当然我们也可以定义其他的provisioner。继续查看节点的信息,会发现容器运行时为containerd:
System Info:
...
Operating System: linux
Architecture: amd64
Container Runtime Version: containerd://1.4.6
...
Karpenter和 Cluster Autoscaler
都会检测NodeSelector, Taints,Tolerations
, 如果同时部署了两者会引起冲突,因为它们同时会检测状态为unschedulable的pod。
将replicas的数量设置为6:
kubectl scale deployment inflate --replicas 6
由于当前的机器资源不足,一些pod的状态变为pending,karpenter检测到后,会将需要的资源进行聚合:
022-05-30T14:53:44.039Z INFO controller.allocation.provisioner/default Starting provisioning loop {"commit": "dc47849"}
2022-05-30T14:53:44.039Z INFO controller.allocation.provisioner/default Waiting to batch additional pods {"commit": "dc47849"}
2022-05-30T14:53:45.460Z INFO controller.allocation.provisioner/default Found 5 provisionable pods {"commit": "dc47849"}
2022-05-30T14:53:45.486Z INFO controller.allocation.provisioner/default Computed packing for 5 pod(s) with instance type option(s) [c4.2xlarge c3.2xlarge c6a.2xlarge c5.2xlarge c5d.2xlarge c6id.2xlarge c5a.2xlarge c5ad.2xlarge c6i.2xlarge c5n.2xlarge m3.2xlarge m5n.2xlarge m6id.2xlarge m4.2xlarge m6i.2xlarge t3a.2xlarge m5ad.2xlarge m5zn.2xlarge m5.2xlarge m5dn.2xlarge] {"commit": "dc47849"}
2022-05-30T14:53:47.800Z INFO controller.allocation.provisioner/default Launched instance: i-03b7945d402f80522, hostname: ip-192-168-69-206.us-west-2.compute.internal, type: t3a.2xlarge, zone: us-west-2a, capacityType: on-demand {"commit": "dc47849"}
2022-05-30T14:53:47.826Z INFO controller.allocation.provisioner/default Bound 5 pod(s) to node ip-192-168-69-206.us-west-2.compute.internal {"commit": "dc47849"}
Karpenter这次挑选的机型如下:
c4.2xlarge c3.2xlarge c6a.2xlarge c5.2xlarge c5d.2xlarge c6id.2xlarge c5a.2xlarge c5ad.2xlarge c6i.2xlarge c5n.2xlarge m3.2xlarge m5n.2xlarge m6id.2xlarge m4.2xlarge m6i.2xlarge t3a.2xlarge m5ad.2xlarge m5zn.2xlarge m5.2xlarge m5dn.2xlarge
注意到有这样一行:
2021-11-15T12:33:18.802Z INFO controller.allocation.provisioner/default Bound 5 pod(s) to node ip-192-168-89-216.eu-west-1.compute.internal {"commit": "6468992"}
和Cluster Autoscaler不同,Karpenter不会等待Kube Schedular来做出调度决策,而是直接将pod绑定在新创建的node上。
将replica的数量设置为0:
kubectl scale deployment inflate --replicas 0
并观察controller的日志:
在上一节中,我们配置了 ttlSecondsAfterEmpty
为30s,所以实例上没有pod后,karpenter在超过这个时间后会终止实例。
group-less
的方式。和Cluster Autoscaler
方式不同,Cluster Autoscaler方式会先评估所有的node group,根据pod的限制,选择出来哪一个是最适合扩容的。