ack-slo-manager提供动态资源超卖功能,通过对节点负载数据的实时收集,可以充分挖掘集群中已分配但未使用的资源量,以实现对集群资源的动态超卖。本文主要介绍如何使用动态资源超卖功能。

前提条件

背景信息

在Kubernetes系统中,Kubelet通过参考Pod的QoS等级来管理单机容器的资源质量,例如OOM(Out of Memory)优先级控制等。Pod的QoS级别分为Guaranteed、Burstable和BestEffort。QoS级别并不是显式定义,而是取决于Pod配置的Request和Limit(CPU、内存)。

为了提高稳定性,应用管理员在提交Guaranteed和Burstable这两类Pod时会预留相当数量的资源Buffer来应对上下游链路的负载波动,在大部分时间段,容器的Request会远高于实际的资源利用率。为了提升集群资源利用率,应用管理员会提交一些QoS为BestEffort的低优任务,来充分使用那些已分配但未使用的资源,实现对集群资源的超卖,其缺点如下:
  • 节点可容纳低优任务的资源量没有任何参考,即使节点实际负载已经很高,由于BestEffort任务在资源规格上缺少容量约束,仍然会被调度到节点上运行。
  • BestEffort任务间缺乏公平性保证,任务资源规格存在区别,但无法在Pod描述上体现。
缺点

针对以上问题,ACK的差异化SLO(Service Level Objectives)提供将这部分资源量化的能力。将上图中的红线定义为Usage,蓝线到红线预留部分资源定义为Buffered,绿色覆盖部分定义为Reclaimed。

如下图所示,Reclaimed资源代表可动态超卖的资源量。ack-slo-manager会根据节点真实负载情况动态更新,并以标准扩展资源的形式实时更新到K8s的Node元信息中。低优的BestEffort任务可以通过在Request和Limit中定义的Recliamed资源配置来使用这部分资源,这部分配置同时也会体现在节点侧的资源限制参数上,保证BestEffort作业之间的公平性。

动态资源超卖

使用限制

组件 版本要求
Kubernetes ≥v1.18
ack-slo-manager ≥0.3.0
Helm版本 ≥v3.0
操作系统 Alibaba Cloud Linux 2、CentOS 7.6、CentOS 7.7

操作步骤

  1. 使用以下命令,查看当前Reclaimed资源总量。
    查看前请确保对应配置已经开启,详见步骤3中的描述。
    #将$nodeName替换为要查询的目标节点名称。
    kubectl get node $nodeName -o yaml
    预期输出:
    #Node
    status:
      allocatable:
        #单位为千分之一核,以下表示50核。
        alibabacloud.com/reclaimed-cpu: 50000
        #单位为字节,以下表示50 GB。
        alibabacloud.com/reclaimed-memory: 53687091200
  2. 创建Pod并申请Reclaimed资源。在Annotation中指定QoS等级,并在Request和Limit中添加对应的Reclaimed资源配置,即可让Pod使用动态超卖资源,具体示例如下。
    #Pod
    metadata:
      annotations:
        #必填,标记为低优先级Pod。
        alibabacloud.com/qosClass: "BE"
    spec:
      containers:
      - resources:
          requests:
            #单位为千分之一核,如下表示1核。
            alibabacloud.com/reclaimed-cpu: "1k"
            #单位为字节,如下表示1 GB。
            alibabacloud.com/reclaimed-memory: "1Gi"
          limits:
            alibabacloud.com/reclaimed-cpu: "1k"
            alibabacloud.com/reclaimed-memory: "1Gi"
    申请Reclaimed资源需注意:
    • 若您通过Deployment或其它类型工作负载提交Pod,只需在对应的模板字段中参照上述示例,采用相同格式填写即可。同一个Pod不能同时申请Reclaimed资源和普通的CPU或Memory资源。
    • 由于节点的Reclaimed资源总量根据当前实际负载动态计算得到,在边界情况下可能会因Kubelet未及时同步而被拒绝,此时您可以直接将被拒绝的Pod进行删除。
    • 受K8s的约束,扩展资源必须以整数形式表达,因此reclaimed-cpu资源需要以千分之一核为单位进行配置。
  3. 管理动态超卖资源。
    节点的Reclaimed容量根据实际的资源利用率情况动态计算得到,计算过程可以按如下公式简单推导:

    reclaimed = nodeAllocatable * thresholdPercent - podUsage(non-BE) - systemUsage

    计算公式中各因子的含义如下:
    • nodeAllocatable:节点可分配资源总量。
    • thresholdPercent:预留水位比例。
    • podUsage(non-BE):高优先级Pod资源真实用量。
    • systemUsage:节点系统资源真实用量。
    其中thresholdPercent为可配置参数,通过修改ConfigMap中的配置项可以实现对资源的灵活管理,配置示例及详细说明如下。
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: slo-manager-config
      namespace: kube-system
    data:
      colocation-config: |
        {
          "enable": true,
          "metricAggregateDurationSeconds": 60,
          "cpuReclaimThresholdPercent": 60,
          "memoryReclaimThresholdPercent": 70
        }
    字段名称 格式 含义
    enable Boolean 表示是否开启节点Reclaimed资源的动态更新,关闭时Reclaimed资源量会被重置为0。默认值为 false
    metricAggregateDurationSeconds Int Reclaimed资源最小更新频率,单位为秒。通常建议保持为1分钟不必修改。
    cpuReclaimThresholdPercent Int 计算节点reclaimed-cpu资源容量时的预留系数。默认值为65,单位为百分比。
    memoryReclaimThresholdPercent Int 计算节点reclaimed-memory资源容量时的预留系数。默认值为65,单位为百分比。
    说明 ack-slo-manager在单机端提供了针对Reclaimed资源的压制和驱逐能力,包括弹性资源限制容器内存服务质量容器L3 Cache及内存带宽隔离,能够有效避免低优的BestEffort容器带来的干扰问题。若您有其他疑问或需求,请提交工单
  4. 执行以下命令,更新ConfigMap。
    使用PATCH方式进行更新,可以避免干扰ConfigMap中其他配置项。
    kubectl patch cm -n kube-system ack-slo-manager-config --patch "$(cat configmap.yaml)"
  5. (可选)通过Prometheus查看Reclaimed资源使用情况。
    • 如果您首次使用该功能的大盘,请进行重置操作,确保已安装动态资源超卖。关于重置的具体操作,请参见重置大盘

      通过ACK控制台Prometheus监控查看Reclaimed资源使用情况的具体操作如下:

      1. 登录容器服务管理控制台
      2. 在控制台左侧导航栏中,单击集群
      3. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情
      4. 在集群管理左侧导航栏中,选择运维管理 > Prometheus监控
      5. Prometheus监控页面,单击动态资源超卖页签。

        您可以在动态资源超卖页签查看详细数据,包括集群以及单个节点的Reclaimed总量和已申请量。更多信息,请参见ARMS Prometheus监控

    • 如果您自建了Prometheus监控,kube-state-metric默认提供了对扩展资源的指标监控,您可以参考以下监控项来配置大盘。
      #节点relcaimed-cpu可分配总量。
      kube_node_status_allocatable{resource="alibabacloud_com_reclaimed_cpu",node="$node"}
      #节点relcaimed-cpu已分配量。
      kube_pod_container_resource_requests{resource="alibabacloud_com_reclaimed_cpu",node="$node"}
      #节点relcaimed-memory可分配总量。
      kube_node_status_allocatable{resource="alibabacloud_com_reclaimed_memory",node="$node"}
      #节点relcaimed-memory已分配量。
      kube_pod_container_resource_requests{resource="alibabacloud_com_reclaimed_memory",node="$node"}

使用样例

  1. 使用以下命令,查看节点Reclaimed资源总量。
    查看前请确保对应配置已经开启,详见步骤3中的描述。
    kubectl get node $nodeName -o yaml

    预期输出:

    #Node信息
    status:
      allocatable:
        #单位为千分之一核,以下表示50核。
        alibabacloud.com/reclaimed-cpu: 50000
        #单位为字节,以下表示50 GB。
        alibabacloud.com/reclaimed-memory: 53687091200
  2. 使用以下YAML内容,创建名为be-pod-demo.yaml文件。
    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        alibabacloud.com/qosClass: BE
      name: be-demo
    spec:
      containers:
      - command:
        - "sleep"
        - "100h"
        image: polinux/stress
        imagePullPolicy: Always
        name: be-demo
        resources:
          limits:
            alibabacloud.com/reclaimed-cpu: "50k"
            alibabacloud.com/reclaimed-memory: "10Gi"
          requests:
            alibabacloud.com/reclaimed-cpu: "50k"
            alibabacloud.com/reclaimed-memory: "10Gi"
      schedulerName: default-scheduler
  3. 使用以下命令,部署be-pod-demo作为目标评测应用。
    kubectl apply -f be-pod-demo.yaml
  4. 在单机端的cgroup分组中查看BE Pod资源限制的生效情况。
    1. 使用以下命令,查看CPU资源限制参数。
      cat /sys/fs/cgroup/cpu,cpuacct/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod4b6e96c8_042d_471c_b6ef_b7e0686a****.slice/cri-containerd-11111c202adfefdd63d7d002ccde8907d08291e706671438c4ccedfecba5****.scope/cpu.cfs_quota_us

      预期输出:

      #容器对应的CPU Cgroup为50核。
      5000000
    2. 使用以下命令,查看Memory资源限制参数。
      cat /sys/fs/cgroup/memory/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod4b6e96c8_042d_471c_b6ef_b7e0686a****.slice/cri-containerd-11111c202adfefdd63d7d002ccde8907d08291e706671438c4ccedfecba5****.scope/memory.limit_in_bytes

      预期输出:

      #容器对应的Memory Cgroup为10 GB。
      10737418240