在Kubernetes中给Pod分配CPU资源

如何限制 Pod 的 CPU 使用

Posted by Brian on Tuesday, September 19, 2023

特性

通过配置运行在集群内容器的CPU请求和限制,可以有效的利用集群上可用的CPU资源。把Pod CPU请求保持在较低的水平,可以使Pod更有机会被调度。通过使CPU限制大于CPU请求,可以完成两件事。

  • Pod 可能会有突发性的活动,它可以利用碰巧可用的 CPU 资源。
  • Pod 在突发负载期间可以使用的 CPU 资源数量仍被限制为合理的数量。

如果不指定CPU限制,有可能发生以下情况之一:

  • 容器在可以使用的 CPU 资源上没有上限。因而可以使用所在节点上所有的可用 CPU 资源。
  • 容器在具有默认 CPU 限制的名字空间中运行,系统会自动为容器设置默认限制。 集群管理员可以使用 LimitRange 指定 CPU 限制的默认值。

如果设置了CPU限制未设置CPU请求,Kubernetes 会自动设置CPU请求为限制的一样的值。

CPU 的单位

CPU 资源以 CPU 单位度量。Kubernetes 中的一个 CPU 等同于:

  • 1 个 AWS vCPU
  • 1 个 GCP核心
  • 1 个 Azure vCore
  • 裸机上具有超线程能力的英特尔处理器上的 1 个超线程

小数值是可以使用的。一个请求 0.5 CPU 的容器保证会获得请求 1 个 CPU 的容器的 CPU 的一半。 你可以使用后缀 m 表示毫。例如 100m CPU、100 milliCPU 和 0.1 CPU 都相同。 精度不能超过 1m。

CPU 请求只能使用绝对数量,而不是相对数量。0.1 在单核、双核或 48 核计算机上的 CPU 数量值是一样的。

比如 500m 等同于 0.5 CPU。所以以后在资源清单中看见CPU的书写为 1 CPU 或 1000m 的时候要知道它们是相等的。

最佳实践

创建一个名为 cpu-example 的 namespace,在此空间下创建的资源与集群的其余部分资源隔离。

kubectl create namespace cpu-example

要为容器指定CPU请求与限制只需要在 resources.requestsresource.limits中增加 cpu清单即可。以下的例子将创建一个Pod并请求0.5CPU并最多限制1CPU。

cpu-request-limit.yaml

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
  namespace: cpu-example
spec:
  containers:
  - name: cpu-demo-ctr
    image: ghcr.io/colinianking/stress-ng
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: "0.5"
    command: 
    - stress-ng
    args:
    - --cpu
    - "2"

可以看在启动参数中 --cpu 尝试使用 2CPU。猜想下会发生什么呢?

  • Pod 无法调度?
  • 虽然尝试使用 2CPU 但限制了最多 1CPU ,所以最终结果应该是 1CPU 左右。

创建Pod

kubectl create -f cpu-request-limit.yaml

查看Pod的运行状态

kubectl get pods -n cpu-example

查看关于Pod的详细信息

kubectl get pod cpu-demo --output=yaml -n cpu-example

输出显示 Pod 中的一个容器的 CPU 请求为 500 milliCPU,并且 CPU 限制为 1 个 CPU。

resources:
  limits:
    cpu: "1"
  requests:
    cpu: 500m

使用 kubectl top 命令来获取该 Pod 的指标:

kubectl top pod cpu-demo -n cpu-example

输出显示 Pod 使用的是 1000 milliCPU,与我们配置限制 1CPU是相符合的。

NAME       CPU(cores)   MEMORY(bytes)
cpu-demo   1000m        9Mi

说明:

CPU 使用率低于 1.0 的另一种可能的解释是,节点可能没有足够的 CPU 资源可用。

删除 Pod

kubectl delete -f cpu-request-limit.yaml

如果设置请求CPU大于节点的所拥有的CPU资源会发生什么?

猜想:

  • Pod 无法进行调度?
  • Pod运行后会全部占用该节点所有的CPU资源?

CPU 请求和限制与都与容器相关, Pod 对 CPU 用量的请求等于 Pod 中所有容器的请求数量之和。 同样,Pod 的 CPU 资源限制等于 Pod 中所有容器 CPU 资源限制数之和。

Pod 调度是基于资源请求值来进行的。 仅在某节点具有足够的 CPU 资源来满足 Pod CPU 请求时。创建以下例子来进行验证:

cpu-request-limit1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo-1
  namespace: cpu-example
spec:
  containers:
  - name: cpu-demo-ctr
    image: ghcr.io/colinianking/stress-ng
    resources:
      limits:
        cpu: "100"
      requests:
        cpu: "100"
    command: 
    - stress-ng
    args:
    - --cpu
    - "2"

创建Pod

kubectl create -f cpu-request-limit1.yaml

查看Pod的运行状态

kubectl get pods -n cpu-example

#Output:
NAME         READY   STATUS    RESTARTS   AGE
cpu-demo-1   0/1     Pending   0          5s

查看有关 Pod 的详细信息,包含事件:

Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  3m39s  default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Insufficient cpu. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod..

输出显示Pod处于Pending状态是无法进行调度的。因为当前节点只有4CPU,而请求 100 CPU远远大于 4CPU。从而导致Pod无法进行调度。

清理资源

kubectl delete namespace cpu-example

清理 namespace 会清理掉该空间下的所有资源。