# 应用扩缩容优先级策略
通过应用扩缩容优先级策略，您可以精细调整Pod在不同类型节点上的扩容和缩容顺序，实现资源管理的最优化。在使用默认扩缩容优先级策略的情况下，扩容过程中Pod优先被调度到包周期的节点，其次被调度到按需计费的节点，最后被调度到virtual-kubelet节点（弹性至CCI）；缩容过程中优先删除virtual-kubelet节点（弹性至CCI）的Pod，其次删除按需计费节点上的Pod，最后删除包周期节点上的Pod。
应用扩缩容优先级策略包括两个方面：
- 针对扩容：集群中新建的Pod，Volcano会按照设定的节点优先级进行调度。
- 针对缩容：指定工作负载时，Volcano会按照设定的节点优先级对其进行打分，用于缩容时决定Pod删除顺序。
 
#### 约束与限制
- 集群版本为v1.23.11及以上、v1.25.6及以上、v1.27.3及以上，以及其他更高版本集群。
- 集群中需安装Volcano调度器插件（1.12.1及以上版本，并在[配置中心 \> 调度配置](https://support.huaweicloud.com/usermanual-cce/cce_10_0785.html)中开启应用扩缩容优先级策略开关）。
- 当前扩缩容优先级功能默认支持对Deployment（也间接包括[ReplicaSet](https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/replicaset/)）生效。若希望对第三方工作负载生效，可以通过高级配置指定，详情请参见[配置第三方工作负载应用扩缩容优先级策略]。
- 若要使用扩容调度优先级策略，需要将工作负载的spec.schedulerName设置成volcano或者将集群默认调度器设置成volcano。目前对于没有设置资源Requests和Limits属性的工作负载，扩容优先级功能不生效。
- 以使用默认优先级策略为例，调度器在调度工作负载时会按照包周期节点 \> 按需节点 \> virtual-kubelet节点（弹性至CCI）的优先级进行调度。但由于调度器会从多个维度对调度结果进行考虑，本优先级策略只是其中一个维度，因此无法百分百确保完全实现上述优先级。
- Volcano调度器存在调度性能和调度结果之间的权衡。当集群存在大量可调度节点时，Volcano出于调度性能的考虑会只选择其中一部分节点来进行调度选择，不会计算全局调度最优解，详情请参见[社区文档链接](https://kubernetes.io/docs/concepts/scheduling-eviction/scheduler-perf-tuning/)。因此该行为与本优先级策略存在冲突，您可以[调整Volcano可调度的节点比例]，来使得Volcano选择所有节点进行调度。
 
#### 应用扩缩容优先级策略介绍
开启应用扩缩容优先级策略，将会在集群中新增两类CRD资源，分别为Balancer与BalancerPolicyTemplate，并创建默认的扩缩容优先级策略，详情请参见[默认应用扩缩容优先级策略]。Volcano插件根据BalancerPolicyTemplate来获取各个节点的优先级，以控制应用扩容时Pod调度的优先级，同时volcano插件基于Balancer和BalancerPolicyTemplate来设置应用缩容时的优先级。
- BalancerPolicyTemplate CRD资源用来进行优先级策略定义。以默认扩缩容优先级策略为例，默认BalancerPolicyTemplate CR资源将会把包周期节点的优先级设置为最高，按需计费节点次之，virtual-kubelet节点（弹性至CCI）设置为最低。 BalancerPolicyTemplate CR资源不支持更新操作。
  
- Balancer CRD资源用来申明扩缩容优先级的作用范围。创建Balancer CR资源时，可以指定某个命名空间下的工作负载作为生效范围，也可以具体指定某个Deployment或者某个ReplicaSet工作负载作为生效范围。
一个Balancer CR资源对应一个BalancerPolicyTemplate CR资源，两者结合共同申明哪些工作负载使用了哪些优先级策略。
插件默认的扩缩容优先级策略通过BalancerPolicyTemplate对象将包周期节点、按需计费节点、virtual-kubelet节点（弹性至CCI）三种类型分成不同的优先级，扩容时，volcano在调度新增Pod时将会考虑这些优先级，优先将Pod调度到优先级高的包周期节点上。
通过Balancer和BalancerPolicyTemplate对象，Volcano插件对Balancer作用范围内的Pod，根据BalancerPolicyTemplate对象定义的优先级分别打上以下注解：
- openvessel.io/workload-balancer-score：表示Pod的分值，对于高优先级节点上的Pod，其对应的分值也相对较大。
- autoscaling.volcano.sh/dominated-by-balancer：表示当前Pod受哪个Balancer对象控制，缩容时会优先缩容分值低的Pod。
![](https://support.huaweicloud.com/usermanual-cce/public_sys-resources/note_3.0-zh-cn.png)
如果您原先的Pod已经存在社区支持的[controller.kubernetes.io/pod-deletion-cost](https://kubernetes.io/zh-cn/docs/reference/labels-annotations-taints/#pod-deletion-cost)注解，那么缩容时将会按照该值定义的优先级来进行缩容。当两个Pod对应controller.kubernetes.io/pod-deletion-cost值相同时，才会按照openvessel.io/workload-balancer-score注解定义的优先级进行缩容。
您可以通过高级配置中的"workload_balancer_score_annotation_key"参数来指定存放Pod分值的注解key，详情请参见[配置第三方工作负载应用扩缩容优先级策略]。
#### 配置应用扩缩容优先级策略
1. 开启应用扩缩容优先级策略开关并成功安装Volcano插件后，会在集群中创建默认扩缩容优先级策略。 
   1. 获取默认Balancer CR资源。
      ```
      # kubectl get balancer default-balancer -oyaml
      apiVersion: autoscaling.volcano.sh/v1alpha1
      kind: Balancer
      metadata:
        name: default-balancer
      spec:
        balancerPolicyTemplateName: default-balancerpolicytemplate
        targets:
        - namespaceSelector:
            matchExpressions:
              - key: kubernetes.io/metadata.name
                operator: Exists
        weight: 10
      ```
      
   
   2. 获取默认BalancerPolicyTemplate CR资源。
      ```
      # kubectl get balancerpolicytemplate default-balancerpolicytemplate -oyaml
      apiVersion: autoscaling.volcano.sh/v1alpha1
      kind: BalancerPolicyTemplate
      metadata:
        name: default-balancerpolicytemplate
      spec:
        policy:
          policyName: Priority
          priorities:
            priorityGroups:
            - priority: 10
              requirements:
              - key: node.cce.io/billing-mode
                operator: In
                values:
                - post-paid
            - priority: 100
              requirements:
              - key: node.cce.io/billing-mode
                operator: In
                values:
                - pre-paid
            - priority: 1
              requirements:
              - key: kubernetes.io/role
                operator: In
                values:
                - virtual-kubelet
                - bursting
      ```
      
   
   
   具体参数含义请参见[默认应用扩缩容优先级策略]。
   
   
2. 部署工作负载，设定实例数为1。 
   当前应用的Pod将会优先调度到包周期节点上。
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: balancer-test
     namespace: default
     labels:
       virtual-kubelet.io/burst-to-cci: 'auto'  #如果集群资源不足时，支持将Pod部署到CCI集群
   spec:
     replicas: 1
     selector:
       matchLabels:
         app: balancer-test
     template:
       metadata:
         labels:
           app: balancer-test
       spec:
         containers:
         - image: nginx:latest
           imagePullPolicy: IfNotPresent
           name: container-1
           resources:
             limits:
               cpu: 250m
               memory: 512Mi
             requests:
               cpu: 250m
               memory: 512Mi
         schedulerName: volcano
   ```
   
   
3. 调整工作负载实例数为5。 
   当前应用的Pod将会优先调度到包周期节点上。在包周期节点资源不足情况下，优先调度到按需计费节点上。在按需计费节点资源不足情况下，优先调度到virtual-kubelet节点（弹性至CCI）。
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: balancer-test
     namespace: default
     labels:
       virtual-kubelet.io/burst-to-cci: 'auto'  #如果集群资源不足时，支持将Pod部署到CCI集群
   spec:
     replicas: 5
     selector:
       matchLabels:
         app: balancer-test
     template:
       metadata:
         labels:
           app: balancer-test
       spec:
         containers:
         - image: nginx:latest
           imagePullPolicy: IfNotPresent
           name: container-1
           resources:
             limits:
               cpu: 250m
               memory: 512Mi
             requests:
               cpu: 250m
               memory: 512Mi
         schedulerName: volcano
   ```
   
   
4. 查看各种类型节点上Pod的分值。 
   1. 包周期节点上的Pod。
      ```
      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          autoscaling.volcano.sh/dominated-by-balancer: default-balancer  #当前Pod通过名为default-balancer的Balancer CR资源控制扩缩优先级
          openvessel.io/workload-balancer-score: "100" #当前包周期节点对应的优先级，也代表着Pod的分值
          ...
        nodeName: 192.168.20.100 #包周期节点
      ```
      
   
   2. 按需计费节点上的Pod。
      ```
      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          autoscaling.volcano.sh/dominated-by-balancer: default-balancer #当前Pod通过名为default-balancer的Balancer CR资源控制扩缩优先级
          openvessel.io/workload-balancer-score "10"  #当前按需计费节点对应的优先级，也代表着Pod的分值
          ...
        nodeName: 192.168.20.196 #按需计费节点
      ```
      
   
   3. virtual-kubelet节点（弹性至CCI）的Pod。
      ```
      apiVersion: v1
      kind: Pod
      metadata:
        annotations:
          autoscaling.volcano.sh/dominated-by-balancer: default-balancer #当前Pod通过名为default-balancer的Balancer CR资源控制扩缩优先级
          openvessel.io/workload-balancer-score: "1"  #当前virtual-kubelet节点对应的优先级，也代表着pod的分值
          ...
        nodeName: virtual-kubelet #virtual-kubelet节点
      ```
      
   
   
   
   
5. 逐步进行工作负载的缩容操作，调小实例数。 
   virtual-kubelet节点（弹性至CCI）的Pod将优先被删除，其次为按需计费节点上的Pod，最后为包周期节点上的Pod。
   
   
 
 #### 默认应用扩缩容优先级策略
使用默认应用扩缩容优先级策略的情况下，集群中存在两个默认CR资源：
- Balancer CRD对应的CR资源
  ```
  apiVersion: autoscaling.volcano.sh/v1alpha1
  kind: Balancer
  metadata:
    name: default-balancer
  spec:
    balancerPolicyTemplateName: default-balancerpolicytemplate
    targets:
    - namespaceSelector:
        matchExpressions:
          - key: kubernetes.io/metadata.name
            operator: Exists
    weight: 10
  ```
  表1Balancer对象关键参数说明 
  | 字段                                | 含义      | 类型       | 备注                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
  |:---|:---|:---|:---|
  | metadata.name                  | 名称      | String | 必填字段。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
  | spec. balancerPolicyTemplateName | 优先级策略名称  | String   | 必填字段。值为集群中相应BalancerPolicyTemplate CR资源名。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
  | spec.targets                    | 优先级策略作用范围 | Slice    | 必填字段。举例： - 针对default命名空间下的应用生效 ``` spec: targets: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: default ```     - 针对default、other、another多个命名空间下的应用生效 ``` spec: targets: - namespaceSelector: matchExpressions: - key: kubernetes.io/metadata.name operator: In values: - default - other - another ```   - 针对所有命名空间下的应用生效 ``` spec: targets: - namespaceSelector: matchExpressions: - key: kubernetes.io/metadata.name operator: Exists ```     - 只针对名为xxx-xxx-xxx，类型为Deployment的应用生效 ``` spec: targets: - objectSelectors: - name: xxx-xxx-xxx kind: Deployment apiVersion: apps/v1 ```   - 只针对命名空间为default，名为xxx-xxx-xxx类型为Deployment的应用生效 ``` spec: targets: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: default objectSelectors: - name: xxx-xxx-xxx kind: Deployment apiVersion: apps/v1 ```    |
  | spec.weight                       | 优先级策略权重 | int32    | 必填字段。在集群存在多个Balancer 对象资源情况下，某个应用可能存在于多个Balancer对象作用范围的交集中，此时选择weight值大的Balancer对象生效。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
     
  
- BalancerPolicyTemplate CRD对应的CR资源
  ```
  apiVersion: autoscaling.volcano.sh/v1alpha1
  kind: BalancerPolicyTemplate
  metadata:
    name: default-balancerpolicytemplate
  spec:
    policy:
      policyName: Priority
      priorities:
        priorityGroups:
        - priority: 10
          requirements:
          - key: node.cce.io/billing-mode
            operator: In
            values:
            - post-paid
        - priority: 100
          requirements:
          - key: node.cce.io/billing-mode
            operator: In
            values:
            - pre-paid
        - priority: 1
          requirements:
          - key: kubernetes.io/role
            operator: In
            values:
            - virtual-kubelet
            - bursting
  ```
  表2BalancerPolicyTemplate对象关键参数说明 
  | 字段                                       | 含义              | 类型      | 备注                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
  |:---|:---|:---|:---|
  | metadata.name                           | 名称              | String | 必填字段。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
  | spec.policy                            | 优先级策略内容           | Struct  | 必填字段。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
  | spec.policy.policyname                   | 优先级策略名           | String | 必填字段。当前只支持名为"Priority"的优先级策略。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
  | spec.policy.priorities. priorityGroups | 优先级策略中定义的具体优先级 | Slice    | 必填字段。举例： - 将包周期节点的优先级设置为100 ``` priorityGroups: - priority: 100 requirements: - key: node.cce.io/billing-mode operator: In values: - pre-paid ```   - 将按需计费节点的优先级设置为10 ``` priorityGroups: - priority: 10 requirements: - key: node.cce.io/billing-mode operator: In values: - post-paid ```   - 将virtual-kubelet/bursting节点的优先级设置为1 ``` priorityGroups: - priority: 1 requirements: - key: kubernetes.io/role operator: In values: - virtual-kubelet - bursting ```    |
     
  
 
#### 自定义应用扩缩容优先级策略
BalancerPolicyTemplate 资源用来进行优先级策略定义，如果用户需要自定义应用扩缩容优先级策略，则需要针对其内容进行修改。
![](https://support.huaweicloud.com/usermanual-cce/public_sys-resources/note_3.0-zh-cn.png)
如果存在多个BalancerPolicyTemplate资源，扩缩策略执行结果将受到这些资源对象的共同作用。因此，如果用户不存在默认扩缩容优先级策略的应用场景，可以执行如下命令对默认优先级策略进行删除。
```
kubectl delete balancerpolicytemplate default-balancerpolicytemplate
```
以"**扩容时优先将工作负载调度到HCE2.0操作系统的节点，其次调度到欧拉操作系统的节点；缩容时优先删除欧拉操作系统节点上的工作负载，其次删除HCE2.0操作系统上的工作负载**"为例：
1. 编写新BalancerPolicyTemplate 资源对象。 
   ```
   vim new-balancerpolicytemplate.yaml
   ```
   内容如下：
   ```
   apiVersion: autoscaling.volcano.sh/v1alpha1
   kind: BalancerPolicyTemplate
   metadata:
     name: new-balancerpolicytemplate
   spec:
     policy:
       policyName: Priority
       priorities:
         priorityGroups:
         - priority: 10    # 设置欧拉操作系统节点优先级为10
           requirements:
           - key: os.name  # 节点操作系统标签
             operator: In
             values:
             - EulerOS_2.0_SP9x86_64  # 可能涉及操作系统的小版本号，用户可以根据自身场景，任意添加
         - priority: 100   # 设置HCE2.0操作系统节点优先级为100
           requirements:
           - key: os.name  # 节点操作系统标签
             operator: In
             values:
             - Huawei_Cloud_EulerOS_2.0_x86_64
   ```
   
   
2. 创建新BalancerPolicyTemplate资源对象。 
   ```
   kubectl create -f new-balancerpolicytemplate.yaml
   ```
   
   
3. 修改default-balancer对象内容，也可以按需进行新建balancer对象 
   ```
   kubectl edit balancer default-balancer
   ```
   修改内容如下：
   ```
   apiVersion: autoscaling.volcano.sh/v1alpha1
   kind: Balancer
   metadata:
     name: default-balancer
   spec:
     balancerPolicyTemplateName: new-balancerpolicytemplate
     targets:
     - namespaceSelector:
         matchExpressions:
           - key: kubernetes.io/metadata.name
             operator: Exists
     weight: 10
   ```
   
   
4. 查看各个Pod的注解中openvessel.io/workload-balancer-score对应的值是否满足预期。 
   EulerOS节点上Pod的openvessel.io/workload-balancer-score注解对应值是10；HCE2.0节点上的pod 的openvessel.io/workload-balancer-score注解对应值是100。
   
   
 
 #### 配置第三方工作负载应用扩缩容优先级策略
若工作负载不是Deployment类型，而是通过CRD进行管理，则可以通过在高级配置中进行相应设置，使volcano支持该工作负载的扩缩容优先级策略。
1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群。
2. 单击左侧导航栏的"配置中心"，在"调度配置"页面，选择Volcano调度器找到对应的"专家模式"，单击"开始使用"。 
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000001989123356.png "点击放大")
   
   
3. 单击左侧导航栏的"插件中心"，在右侧找到Volcano调度器，单击"安装"或"编辑"，并在"参数配置"中设置Volcano调度器配置参数。
4. 指定需要支持的第三方工作负载类型，JSON示例如下： 
   ```
   {
       "default_scheduler_conf": {
   ...
       },
       "workload_balancer_score_annotation_key": "controller.kubernetes.io/pod-deletion-cost",
       "workload_balancer_third_party_types": "apps.kruise.io/v1alpha1/clonesets,apps.kruise.io/v1beta1/statefulsets"
   }
   ```
   - workload_balancer_score_annotation_key：指定Pod的分值注解key，目前支持"openvessel.io/workload-balancer-score"或者"controller.kubernetes.io/pod-deletion-cost"，除此之外的值会导致volcano异常退出。
   
   - workload_balancer_third_party_types：第三方工作负载的group + version + kind拼接成的字符串，多个CRD间以英文逗号分隔。 例如"apps.kruise.io/v1alpha1/clonesets,apps.kruise.io/v1beta1/statefulsets"，注意kind需要为复数形式，例如 "apps.kruise.io/v1alpha1/cloneset"的非复数形式会导致监听不到对应的CRD。
     如果格式错误，会导致volcano异常退出；如果指定的CRD在集群上不存在，会导致应用扩缩容优先级策略无法正常工作。
     
   
   
   **若期望配置的CRD可以按照优先级缩容，则需要管理该CRD的controller可以在缩容时感知到Pod的分值注解，并按照得分控制缩容顺序。**
   
   
 
 #### 附录：调整Volcano可调度的节点比例
编写volcano-scheduler资源对象。
```
kubectl edit deploy volcano-scheduler -nkube-system
```
内容如下：
```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: volcano-scheduler
    app.kubernetes.io/managed-by: Helm
    release: cceaddon-volcano
  name: volcano-scheduler
  namespace: kube-system
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: volcano-scheduler
  strategy:
    rollingUpdate:
      maxSurge: 10%
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: volcano-scheduler
        release: cceaddon-volcano
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - volcano-scheduler
              topologyKey: topology.kubernetes.io/zone
            weight: 100
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - volcano-scheduler
            topologyKey: kubernetes.io/hostname
      containers:
      - command:
        - /bin/sh
        - -c
        - /volcano-scheduler --leader-elect=true --lock-object-namespace=kube-system
          --feature-gates=CSIMigrationFlexVolumeFuxi=true,CSIMigrationFlexVolumeFuxiComplete=true,MultiGPUScheduling=true
          --kube-api-qps=200 --alsologtostderr --listen-address=$(MY_POD_IP):8080
          --enable-healthz=true --healthz-address=$(MY_POD_IP):11251 --enable-metrics=true --percentage-nodes-to-find=100
          --scheduler-conf=/volcano.scheduler/default-scheduler.conf -v=3 1>>/var/log/volcano/volcano-scheduler.log
```
其中**--percentage-nodes-to-find=100**表示Volcano在进行调度选择时可以遍历集群中的所有节点。
