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


先决条件

  1. 集群必须绑定OIDC
  2. 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

# 下载安装文件
wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

修改之处一(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


总结:




  1. 集群配置了CA,有且只有pod出现pending的时候,会触发扩容的动作

  1. 如果一个node节点在10分钟之后,没有运行pod,则会被缩容释放. 该时间可以调整:--scale-down-delay-after-add=5m
  2. 注意事项: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#common-notes-and-gotchas
  3. 如果想要根据node的cpu或者内存的使用率来进行扩容或者缩容,需要结合ASG自带的进行操作(动态伸缩策略)
  4. 或者利用CloudWatch告警进行伸缩
  5. 如果pod默认调度策略,则可能会分配到打标签的节点组上,但一定不会分布到带有污点的节点组上
  6. 如果pod有节点亲和(标签),则pod会被调度到满足标签匹配的节点组上,但一定不会分布到带有污点的节点组上
  7. 如果pod有节点亲和和污点容忍,则pod会被调度到满足标签匹配的节点组上,也会被分布到能容忍污点的节点组上