EKS弹性伸缩
Autoscaling 是一项功能,可以自动扩缩资源以满足您不断变化的需求。若没有此项重要的 Kubernetes 功能,则需要耗费大量的人力资源来手动执行这些工作。
Amazon EKS 支持两款自动扩缩产品:
- Karpenter
- Karpenter 是一款灵活、高性能 Kubernetes 集群自动缩放器,可帮助提高应用程序可用性和集群效率。只需不到一分钟时间,Karpenter 即可启动适当规模的计算资源(例如 Amazon EC2 实例)来响应不断变化的应用程序负载。通过将 Kubernetes 与 Amazon 相集成,Karpenter 可以即时预置精准满足工作负载需求的计算资源。Karpenter 会根据集群工作负载的具体需求来自动调配新的计算资源。这包括计算、存储、加速和调度需求。Amazon EKS 支持使用 Karpenter 的集群,但 Karpenter 可以与任何合规的 Kubernetes 集群配合使用。有关更多信息,请参阅 Karpenter 文档。
- Cluster Autoscaler
- 当容器组(pod)失败或被重新安排到其他节点时,Kubernetes Cluster Autoscaler 会自动调整集群中的节点数。Cluster Autoscaler 使用自动扩缩组。有关更多信息,请参阅 Amazon 上的 Cluster Autoscaler
先决条件
- 集群必须绑定OIDC
- ASG必须包含以下标签:(eksctl工具创建会自动添加标签) k8s.io/cluster-autoscaler/enabled k8s.io/cluster-autoscaler/
CA伸缩实践
官网参考地址: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md
创建一个策略
思路: 创建一个策略,然后利用策略绑定至对应的角色,最后在serviceaccount中使用该角色
###准备一个策略文件
cat > policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeScalingActivities",
"autoscaling:DescribeTags",
"ec2:DescribeInstanceTypes",
"ec2:DescribeLaunchTemplateVersions"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
"ec2:DescribeImages",
"ec2:GetInstanceTypesFromInstanceRequirements",
"eks:DescribeNodegroup"
],
"Resource": ["*"]
}
]
}
EOF
###创建一个策略
aws iam create-policy --policy-name AmazonEKSClusterAutoscalerPolicy --policy-document file://policy.json
创建一个角色
如下图:
下一步选择之前创建的策略
接下来输入一个角色名称,然后点击完成
需要修改授信任实体的部份信息(重要)
aud修改成: sub
sts.amazonaws.com: 修改为system:serviceaccount:kube-system:cluster-autoscaler
修改后如图:
部署CA
修改之处一(name)
vim cluster-autoscaler-autodiscover.yaml
修改集群的名字:
修改之处二(sa)
执行安装
kubectl apply -f cluster-autoscaler-autodiscover.yaml
观察日志
kubectl logs -f -l app=cluster-autoscaler -n kube-system ###确保没有ERROR.这里一般错误是sa的权限没有正确授权导致的
单节点组
扩容
kubectl create deploy nginx --replicas=10
kubectl scale deploy nginx --replicas=100
在EKS控制平面可以看到对应信息:
缩容
多节点组测试
环境说明
nodegroup节点组描述: 有标签 role=works
lemon-ng02节点组描述: 有标签 app=lemon
lemon-ng03节点组描述: 有标签 app=lemon 有污点 game=mihoyo:NoSchedule
测试一(默认调度)
Yaml文件
#测试yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
replicas: 6
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.22
imagePullPolicy: IfNotPresent
name: nginx
restartPolicy: Always
扩容之后,发现会分布在三台机器
会分布在nodegroup节点组和lemon-ng02节点组.但是绝不会分布在lemon-ng03(因为该节点有污点)
总结: 如果创建的deploy,采用默认的调度策略.则会在节点组nodegroup和lemon-ng01进行随机分布.
缩容生效时间为默认10分钟
亲和与容忍度
节点亲和性 是 Pod 的一种属性,它使 Pod 被吸引到一类特定的节点 (这可能出于一种偏好,也可能是硬性要求)。 污点(Taint) 则相反——它使节点能够排斥一类特定的 Pod。
容忍度(Toleration) 是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。 容忍度允许调度但并不保证调度:作为其功能的一部分, 调度器也会评估其他参数。
污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod, 是不会被该节点接受的。
思考以下场景:
一个带有gpu类型的node,如何才能被指定的pod给成功调度到该节点之上?
1. 先对这个node打一个污点,避免被任意pod调度上来
2. 对pod设置污点容忍,容忍这个节点的污点
通过上面的两个步骤即可完成操作。把pod调度到指定的node节点上
感兴趣的话,可以根据官网进行实际操作一下
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/
https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/
测试二(节点亲和)
简单理解: 亲和可以是pod与node之前的亲和,也可以是pod与pod之间的亲和。比如: pod需要被调度在指定的node节点之上,或者pod需要和指定的pod运行在一起。具有以下特点:
1. 硬件特性:当节点具有特定的硬件特性(比如GPU、特殊的处理器等)时,可以使用节点亲和性确保需要这些硬件资源的Pod被调度到具有相应硬件的节点上。这有助于优化性能,使得需要特殊硬件支持的任务能够在相应的节点上执行。
2. 数据本地性: 如果应用程序依赖于某些数据,为了减少网络开销,可以使用节点亲和性将Pod调度到存储有相关数据的节点上。这确保了容器可以更快地访问本地数据,提高了应用程序的响应速度。
3. 地理位置:在分布式系统中,有时候希望将Pod调度到离特定地理位置更近的节点上,以减少网络延迟。通过节点亲和性,可以指定Pod应该在哪个地理位置的节点上运行。
4. 特定节点的负载:当集群中的某些节点具有更高的计算能力或资源时,可以使用节点亲和性确保需要更多资源的Pod被调度到这些节点上,从而实现资源的合理分配。
Yaml文件
#节点亲和
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.20
name: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #硬亲和。必须满足,如果不满足则不调度则会出现pending
nodeSelectorTerms:
- matchExpressions: #多个matchExpressions,匹配其中一个即可
- key: app
operator: In #只有一个value是匹配成功也可以调度
values:
- lemon
说明: 按照上面的yaml文件,该deploy会运行在lemon-ng02上面.因为lemon-02上面符合要求. 虽然lemon-ng03也有对应的标签,但是因为lemon-ng03有污点,因此不会被调度上去
扩容: kubectl scale deploy nginx --replicas=50
缩容: kubectl delete deploy nginx
测试三:(节点亲和+污点容忍)
当配置了污点容忍和节点亲和的情况下。调度器在调度该pod的时候,就会进行两层筛选。一个是污点容忍,一个是节点亲和
如果node满足亲和,但是有污点。默认情况下,pod还是会pending。因为不能容忍污点,因此没办法调度
如果node满足亲和,且pod设置了容忍污点,这种情况会被调度。
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/
https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/
Yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.20
name: nginx
tolerations: # 容忍
- key: "game" # key
operator: "Equal" # 等于,这里要严格匹配k和v的值
value: "mihoyo" # value1
effect: "NoSchedule" # 容忍不被调度
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #硬亲和。必须满足,如果不满足则不调度则会出现pending
nodeSelectorTerms:
- matchExpressions: #多个matchExpressions,匹配其中一个即可
- key: app
operator: In #只有一个value是匹配成功也可以调度
values:
- lemon
扩容: kubectl scale deploy nginx --replicas=100
这里的节点组: 会扩容lemon-ng02或者lemon-ng03
缩容: kubectl scale deploy nginx --replicas=10
总结:
- 集群配置了CA,有且只有pod出现pending的时候,会触发扩容的动作
- 如果一个node节点在10分钟之后,没有运行pod,则会被缩容释放. 该时间可以调整:--scale-down-delay-after-add=5m
- 注意事项: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#common-notes-and-gotchas
- 如果想要根据node的cpu或者内存的使用率来进行扩容或者缩容,需要结合ASG自带的进行操作(动态伸缩策略)
- 或者利用CloudWatch告警进行伸缩
- 如果pod默认调度策略,则可能会分配到打标签的节点组上,但一定不会分布到带有污点的节点组上
- 如果pod有节点亲和(标签),则pod会被调度到满足标签匹配的节点组上,但一定不会分布到带有污点的节点组上
- 如果pod有节点亲和和污点容忍,则pod会被调度到满足标签匹配的节点组上,也会被分布到能容忍污点的节点组上

























