Kubernetes 资源预留

416 阅读9分钟

Node Allocatable Resources

Allcatable

除了 kubelet、runtime 等 kubernetes 守护进程和用户 pod 之外,Kubernetes 节点通常还运行许多操作系统系统守护进程。 Kubernetes 假设节点中的所有可用计算资源(称为容量)都可用于用户 Pod。 实际上,系统守护进程使用大量资源,它们的可用性对于系统的稳定性至关重要。 为了解决这个问题,该提案引入了 Allocatable 的概念,它标识了用户 Pod 可用的计算资源量。 具体来说,kubelet 将提供一些旋钮来为 OS 系统守护进程和 kubernetes 守护进程保留资源

Kubernetes 的节点可以按照 Capacity调度。默认情况下 pod 能够使用节点全部可用容量。 但这样也存在问题,因为节点自己通常运行了不少驱动 OS 和 Kubernetes 的系统守护进程。 除非为这些系统守护进程留出资源,否则它们将与 pod 争夺资源并导致节点资源短缺问题。kubelet公开了一个名为node allocatable的特性,有助于为系统守护进程预留计算资源。 Kubernetes 推荐集群管理员按照每个节点上的工作负载密度配置node allocatable

            Node Capacity
    ---------------------------
    |     kube-reserved       |
    |-------------------------|
    |     system-reserved     |
    |-------------------------|
    |    eviction-threshold   |
    |-------------------------|
    |      allocatable        |
    |   (available for pods)  |
    ---------------------------
Node Capacity 是指Kubernetes Node所有资源总量
Kube-reserved是指为Kubernetes组件预留的资源量,如(Docker deamon, kubelet, kube proxy)
System-reserved是指为系统守护进程预留的资源量,如不受kubernetes 管理的进程、一般涵盖在/system 下的raw container的所有进程
eviction-threshold是指节点的驱逐策略,根据kubelet启动时注入的参数(--eviction-hard等其它)设定的阈值,如果触发该阈值,kubelet会根据Kubenetes中的Qos的等级进行驱逐Pod
allocatable    是指节点上的Pod所完全能够分配的资源,具体公式如:[Allocatable] = [Node Capacity] - [Kube-Reserved] - [System-Reserved] - [Hard-Eviction-Threshold]

Kubernetes 节点上的 Allocatable 被定义为 pod 可用计算资源量。调度器不会超额申请 Allocatable。 目前支持 CPU, memory 和 ephemeral-storage 这几个参数

Kube-Reserved

kubereserved是为kubernetes组件预留资源而设立的参数配置,设置此参数必须需要重启kubelet(在kublet启动时通过cmd-line引入),因此kubelet正常运行时无法将其更改(不排除在以后的版本fix这一缺陷实现热加载)

--kube-reserved=cpu=500m,memory=500Mi

早期的功能仅支持CPU & MEM资源预留,但在以后kubernetes会相继支持更多的资源限制,比如本地存储 & IO 权重以实现kubernetes node的资源分配可靠性

System-Reserved

最初实现,systemreserved 与 kubereserved 的功能是一样的,同样都是资源预留功能,但是二者的意义是不同的,很明显kubereserved是为kubernetes组件实现资源预留;而systemreserved是为非kubernetes组件的系统进程而预留的资源值

Evictions Thresholds

为了提高节点的可靠性,每当节点内存或本地存储耗尽时,kubelet 都会驱逐 pod, evictions & node allocatable可共同有助于提高节点稳定性

自1.5版本开始,evictions是基于节点整体的capacity的使用情况,kubelet驱逐pod是基于Qos与自定义的eviction thresholds,更多的细节请参考文档

从1.6版本开始,默认情况下,节点上的所有pod使用 cgroups 强制执行 Allocatable,pod 不能超过 Allocatable的值,cgroups强制执行 meory & cpu resource.limits

  • --kube-reserved

kubernetes 系统预留的资源配置,以一组 ResourceName=ResourceQuantity 格式表示。(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi)。当前支持用于根文件系统的 CPU、内存(memory)和本地临时存储。请参阅 kubernetes.io/docs/user-g… 获取更多信息。(默认值为 none)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 kubernetes.io/docs/tasks/…

  • --kube-reserved-cgroup

通过--kube-reserved参数配置为 kubernetes 组件其保留计算资源而设置的最顶层cgroup的绝对路径,与--kube-reserved相呼应,成对配置

Example /kube.slice

  • --system-reserved

系统预留的资源配置,以一组 ”ResourceName=ResourceQuantity“ 的格式表示,(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi)。目前仅支持 CPU 和内存(memory)的设置【官方原文,但是可以支持本地存储限额配置】 。请参考 kubernetes.io/docs/user-g… 获取更多信息。(默认值为 ”none“)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 kubernetes.io/docs/tasks/…

  • --system-reserved-cgroup

简单来讲就是使用--system-reserved为非Kubernetes组件的系统进程而预留的一部分资源,就等于是为系统进程预留的资源配置,但是必须设置--system-reserved的最顶层的cgroup的绝对路径,(默认值为 ‘’ 空)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 kubernetes.io/docs/tasks/…

Example /system.slice

  • --eviction-hard 

强驱逐阈值,代表如果触发此值,立即驱逐节点的Pod,具体如何驱逐Pod则根本Kubernetes定义的Qos等级(例如:memory.available < 1Gi(内存可用值小于 1 G))设置。(默认值为 imagefs.available<15%,memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 kubernetes.io/docs/tasks/…

配置过程

规则说明:如果--enforce-node-allocatable(enforceNodeAllocatable)指定systemReserved & kubeReserved值时,那么必须配置对应的cgroup参数(systemReservedCgroup & kubeReservedCgroup),相反如果enforceNodeAllocatable没有指定(systemReserved & kubeReserved)则不会生效,虽然从kubectl describe nodes看到的Allocatable的值减少,但是并没有真正限制Kubernetes组件及OS守护进程的资源限制,也就说OS守护进程及组件在资源请求分配时是无限的

解释说明:为什么Kubernetes官方默认并没有限制kubeReserved & systemReserved是因为它他们资源使用很难控制,如果设置不当后果很严重直接会影响整个平台或者是OS无法正常运行,将是致命性问题,但是Kubernetes保留了evictionHard默认驱逐策略

  • 具体配置如下

    "evictionHard": {
          "imagefs.available": "15%",
          "memory.available": "100Mi",
          "nodefs.available": "10%",
          "nodefs.inodesFree": "5%"
        }
    
  • 验证参数设置关联性

    开启kubelet日志等级模式,如下

    <root@HK-K8S-WN4 /var/lib/kubelet># cat kubeadm-flags.env 
    #KUBELET_KUBEADM_ARGS="--cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2"
    # 上面--cgroup-driver=systemd 因为在新版本此方法虽然还可以使用,但是启动时会报错,需要在config.yaml配置,所以删除了此部分配置,具体配置如下文
    KUBELET_KUBEADM_ARGS="--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.2 --v=5"
    

 

配置kubeReserved(具体的配置在/var/lib/kubelet目录下,配置文件config.yaml安装之后默认生成的配置文件,当然kubelet启动的时候会指向该配置--config=/var/lib/kubelet/config.yaml)默认kubeadm配置文件/var下,由systemctl cat kubelet指向此文件

  • 文件主要配置
    # 只开启对kube-reserved资源预留
    enforceNodeAllocatable:
      - pods
      - kube-reserved
    # - system-reserved
    # 以下仅仅是验证,是在以上enforceNodeAllocatable只开启kube-reserved时,但下文同时一配置kubeRserved & systemReserved,在kubelet启动时是否报错
    systemReserved:
      cpu: 200m
      memory: 2000Mi
    kubeReserved:
      cpu: 200m
      memory: 500Mi
    kubeReservedCgroup: /kube.slice
    systemReservedCgroup: /system.slice
    cgroupDriver: systemd
    maxPods: 64
    

查询节点可分配资源

执行以下命令,查看节点的资源总量和可分配资源。

** **

kubectl describe node [NODE_NAME] | grep Allocatable -B 7 -A 6

预期输出:

** **

Capacity:
  cpu:                4                 #节点的CPU总核数。
  ephemeral-storage:  123722704Ki       #节点的临时存储总量,单位KiB。
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             7925980Ki         #节点的内存总量,单位KiB。
  pods:               64
Allocatable:
  cpu:                3900m             #节点可分配的CPU核数。
  ephemeral-storage:  114022843818      #节点可分配的临时存储,单位Byte。
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             5824732Ki         #节点可分配的内存,单位KiB。
  pods:               64

计算节点可分配资源

可分配资源的计算公式:可分配资源(Allocatable) = 总资源(Capacity)-预留资源(Reserved)-驱逐阈值(Eviction-Threshold)

公式说明:

  • 总资源对应查询节点命令输出中的Capacity字段。
  • 关于预留资源的相关信息,请参见资源预留策略
  • 关于驱逐阈值的相关信息,请参见节点压力驱逐

资源预留策略

节点的预留资源量通常要考虑以下因素:

  • 由于规格较高的ECS节点通常会运行更多的Pod,为了保证节点的性能,ACK会为Kubernetes组件预留更多资源。
  • 由于Windows节点需要使用额外的资源来运行Windows操作系统和Windows Server相关组件,Windows节点通常会比Linux节点需要更多的预留资源。更多信息,请参见创建Windows节点池

预留资源包括给kube组件预留的资源(kubeReserved)和给system进程预留的资源(systemReserved)。kubeReserved和systemReserved各占预留资源的50%。例如,节点总CPU 1 Core,则预留CPU为100 milliCore,其中kubeReserved占用50 milliCore,systemReserved占用50 milliCore。修改资源预留的值,请参见自定义节点池kubelet配置

ACK会根据CPU和内存所在的不同区间来计算预留的资源量,节点的总预留资源量等于各区间的预留资源量之和。

  • CPU:计算节点的总CPU预留量示意图如下。预留资源策略

    以32核的节点为例,总的CPU预留量计算如下:

    100+(32000-4000)×2.5%=800 milliCore

  • 内存:计算节点的总内存预留量示意图如下所示。总内存预留量

    以256 GiB内存的节点为例,总的内存预留量计算如下:

    4×25%+(8-4)×20%+(16-8)×10%+(128-16)×6%+(256-128)×2%=11.88 GiB

ACK节点预留资源示例

********
节点总资源预留资源
CPU(单位:Core)Memory(单位:GiB)CPU(单位:milliCore)Memory(单位:MiB)
12100512
241001024
481001843
8162002662
16324003645
32648005611
6412816009543
128256240012164
256512304017407
5121024432027893

常见问题

如何查看节点总CPU和内存?

CPU

执行如下命令,查询节点总CPU。

cat /proc/cpuinfo | grep processor

预期输出:

processor       : 0
processor       : 1
processor       : 2
processor       : 3

内存

执行如下命令,查询节点总内存。

cat /proc/meminfo | grep MemTotal

预期输出:

MemTotal:        7660952 kB

参考文献:

kubernetes官网【 Pod 优先级和抢占 】

Kubernetes 资源预留(一)

阿里 ACK 节点资源预留策略