# 给容器和 Pod 分配 CPU 资源

这个教程指导如何给容器分配请求的 CPU 资源和配置 CPU 资源限制,我们保证容器可以拥有 所申请的 CPU 资源,但是并不允许它使用超过限制的 CPU 资源。

# 开始之前

您需要有一个 k8s 集群,并且必须配置 kubectl 命令行工具以与集群通信。如果您还没有集群,可以使用 Minikube 创建一个集群。

集群里的每个节点至少需要 1 个 CPU。

这篇教程里的少数步骤可能要求你的集群运行着 Heapster 如果你没有 Heapster,也可以完成大部分步骤,就算跳过 Heapster 的那些步骤,也不见得会有什么问题。

判断 Heapster 服务是否正常运行,执行以下命令:

kubectl get services --namespace=kube-system

如果 heapster 正常运行,命令的输出应该类似下面这样:

NAMESPACE    NAME      CLUSTER-IP    EXTERNAL-IP  PORT(S)  AGE
kube-system  heapster  10.11.240.9   <none>       80/TCP   6d

# 创建一个命名空间

创建一个命名空间,可以确保你在这个实验里所创建的资源都会被有效隔离,不会影响你的集群。

kubectl create namespace cpu-example

# 声明一个 CPU 申请和限制

给容器声明一个 CPU 请求,只要在容器的配置文件里包含这么一句 resources:requests 就可以,声明一个 CPU 限制,则是这么一句 resources:limits.

在这个实验里,我们会创建一个只有一个容器的 Pod,这个容器申请 0.5 个 CPU,并且 CPU 限制设置为 1. 下面是配置文件:

cpu-request-limit.yaml
apiVersion: v1 kind: Pod metadata: name: cpu-demo spec: containers: - name: cpu-demo-ctr image: vish/stress resources: limits: cpu: "1" requests: cpu: "0.5" args: - -cpus - "2"

在这个配置文件里,整个 args 段提供了容器所需的参数。 -cpus "2"代码告诉容器尝试使用 2 个 CPU 资源。

创建 Pod:

kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/cpu-request-limit.yaml --namespace=cpu-example

验证 Pod 的容器是否正常运行:

kubectl get pod cpu-demo --namespace=cpu-example

查看 Pod 的详细信息:

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

输出显示了这个 Pod 里的容器申请了 500m 的 cpu,同时 CPU 用量限制为 1.

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

启用 proxy 以便访问 heapster 服务:

kubectl proxy

在另外一个命令窗口里,从 heapster 服务读取 CPU 使用率。

curl http://localhost:8001/api/v1/proxy/namespaces/kube-system/services/heapster/api/v1/model/namespaces/cpu-example/pods/cpu-demo/metrics/cpu/usage_rate

输出显示 Pod 目前使用 974m 的 cpu,这个刚好比配置文件里限制的 1 小一点点。

{
 "timestamp": "2017-06-22T18:48:00Z",
 "value": 974
}

还记得我吗设置了-cpu "2", 这样让容器尝试去使用 2 个 CPU,但是容器却只被运行使用 1 一个,因为容器的 CPU 使用被限制了,因为容器尝试去使用超过其限制的 CPU 资源。

注意: 有另外一个可能的解释为什么 CPU 会被限制。因为这个节点可能没有足够的 CPU 资源,还记得我们 这个实验的前提条件是每个节点都有至少一个 CPU,如果你的容器所运行的节点只有 1 个 CPU,那容器就无法 使用超过 1 个的 CPU 资源,这跟 CPU 配置上的限制以及没关系了。

# CPU 单位

CPU 资源是以 CPU 单位来计算的,一个 CPU,对于 k8s 而言,相当于:

  • 1 AWS vCPU
  • 1 GCP Core
  • 1 Azure vCore
  • 1 Hyperthread on a bare-metal Intel processor with Hyperthreading

小数值也是允许的,一个容器申请 0.5 个 CPU,就相当于其他容器申请 1 个 CPU 的一半,你也可以加个后缀 m 表示千分之一的概念。比如说 100m 的 CPU,100 豪的 CPU 和 0.1 个 CPU 都是一样的。但是不支持精度超过 1M 的。

CPU 通常都是以绝对值来申请的,绝对不能是一个相对的数值;0.1 对于单核,双核,48 核的 CPU 都是一样的。

删除 Pod:

kubectl delete pod cpu-demo --namespace=cpu-example

# 请求的 CPU 超出了节点的能力范围

CPU 资源的请求和限制是用于容器上面的,但是认为 POD 也有 CPU 资源的申请和限制,这种思想会很有帮助。 Pod 的 CPU 申请可以看作 Pod 里的所有容器的 CPU 资源申请的总和,类似的,Pod 的 CPU 限制就可以看出 Pod 里 所有容器的 CPU 资源限制的总和。

Pod 调度是基于请求的,只有当 Node 的 CPU 资源可以满足 Pod 的需求的时候,Pod 才会被调度到这个 Node 上面。

在这个实验当中,我们创建一个 Pod 请求超大的 CPU 资源,超过了集群里任何一个 node 所能提供的资源。 下面这个配置文件,创建一个包含一个容器的 Pod。这个容器申请了 100 个 CPU,这应该会超出你集群里 任何一个节点的 CPU 资源。

cpu-request-limit-2.yaml
apiVersion: v1 kind: Pod metadata: name: cpu-demo-2 spec: containers: - name: cpu-demo-ctr-2 image: vish/stress resources: limits: cpu: "100" requests: cpu: "100" args: - -cpus - "2"

创建 Pod:

kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/cpu-request-limit-2.yaml --namespace=cpu-example

查看 Pod 的状态:

kubectl get pod cpu-demo-2 --namespace=cpu-example

这个输出显示 Pod 正处在 Pending 状态,那是因为这个 Pod 并不会被调度到任何节点上,所以它会 一直保持这种状态。

kubectl get pod cpu-demo-2 --namespace=cpu-example
NAME         READY     STATUS    RESTARTS   AGE
cpu-demo-2   0/1       Pending   0          7m

查看 Pod 的详细信息,包括记录的事件:

kubectl describe pod cpu-demo-2 --namespace=cpu-example

这个输出显示了容器无法被调度因为节点上没有足够的 CPU 资源:

Events:
  Reason      Message
  ------      -------
  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient cpu (3).

删除 Pod:

kubectl delete pod cpu-demo-2 --namespace=cpu-example

# 如果不指定 CPU 限额呢

如果你不指定容器的 CPU 限额,那下面所描述的其中一种情况会出现:

  • 容器使用 CPU 资源没有上限,它可以使用它运行的 Node 上所有的 CPU 资源。
  • 容器所运行的命名空间有默认的 CPU 限制,这个容器就自动继承了这个限制。集群管理可以使用 限额范围 来指定一个默认的 CPU 限额。

# 设置 CPU 申请和限制的动机

通过配置集群里的容器的 CPU 资源申请和限制,我们可以更好的利用集群中各个节点的 CPU 资源。 保持 Pod 的 CPU 请求不太高,这样才能更好的被调度。设置一个大于 CPU 请求的限制,可以获得以下 两点优势:

  • Pod 在业务高峰期能获取到足够的 CPU 资源。
  • 能将 Pod 在需求高峰期能使用的 CPU 资源限制在合理范围。

# 清理

删除你的命名空间:

kubectl delete namespace cpu-example
Last Updated: 4/15/2023, 8:33:17 PM