×

CPU 管理器管理 CPU 组并将工作负载限制在特定 CPU 上。

CPU 管理器对于具有以下某些属性的工作负载非常有用:

  • 需要尽可能多的 CPU 时间。

  • 对处理器缓存未命中敏感。

  • 是低延迟网络应用程序。

  • 与其他进程协调并受益于共享单个处理器缓存。

拓扑管理器收集来自 CPU 管理器、设备管理器和其他提示提供者的提示,以对齐 Pod 资源(例如 CPU、SR-IOV VF 和其他设备资源),用于同一非统一内存访问 (NUMA) 节点上的所有服务质量 (QoS) 类别。

拓扑管理器使用收集到的提示中的拓扑信息来确定是否可以根据配置的拓扑管理器策略和 Pod 请求的资源在节点上接受或拒绝 Pod。

拓扑管理器对于使用硬件加速器来支持延迟关键执行和高吞吐量并行计算的工作负载非常有用。

要使用拓扑管理器,必须使用`static`策略配置 CPU 管理器。

设置 CPU 管理器

要配置 CPU 管理器,请创建 KubeletConfig 自定义资源 (CR) 并将其应用于所需节点集。

步骤
  1. 运行以下命令为节点添加标签:

    # oc label node perf-node.example.com cpumanager=true
  2. 要为所有计算节点启用 CPU 管理器,请运行以下命令编辑 CR:

    # oc edit machineconfigpool worker
  3. custom-kubelet: cpumanager-enabled标签添加到metadata.labels部分。

    metadata:
      creationTimestamp: 2020-xx-xxx
      generation: 3
      labels:
        custom-kubelet: cpumanager-enabled
  4. 创建一个KubeletConfigcpumanager-kubeletconfig.yaml,自定义资源 (CR)。请参考上一步中创建的标签,以便使用新的 kubelet 配置正确更新节点。请参阅machineConfigPoolSelector部分

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: cpumanager-enabled
    spec:
      machineConfigPoolSelector:
        matchLabels:
          custom-kubelet: cpumanager-enabled
      kubeletConfig:
         cpuManagerPolicy: static (1)
         cpuManagerReconcilePeriod: 5s (2)
    1 指定策略
    • none。此策略显式启用现有的默认 CPU 亲和性方案,除了调度程序自动执行的操作之外,不提供任何亲和性。这是默认策略。

    • static。此策略允许具有整数 CPU 请求的保证型 Pod 中的容器。它还限制对节点上独占 CPU 的访问。如果为static,则必须使用小写字母s

    2 可选。指定 CPU 管理器协调频率。默认为5s
  5. 运行以下命令创建动态 kubelet 配置:

    # oc create -f cpumanager-kubeletconfig.yaml

    这会将 CPU 管理器功能添加到 kubelet 配置,并且如果需要,机器配置操作员 (MCO) 将重新引导节点。要启用 CPU 管理器,无需重新引导。

  6. 运行以下命令检查合并的 kubelet 配置:

    # oc get machineconfig 99-worker-XXXXXX-XXXXX-XXXX-XXXXX-kubelet -o json | grep ownerReference -A7
    示例输出
           "ownerReferences": [
                {
                    "apiVersion": "machineconfiguration.openshift.io/v1",
                    "kind": "KubeletConfig",
                    "name": "cpumanager-enabled",
                    "uid": "7ed5616d-6b72-11e9-aae1-021e1ce18878"
                }
            ]
  7. 运行以下命令检查计算节点的更新的kubelet.conf文件:

    # oc debug node/perf-node.example.com
    sh-4.2# cat /host/etc/kubernetes/kubelet.conf | grep cpuManager
    示例输出
    cpuManagerPolicy: static        (1)
    cpuManagerReconcilePeriod: 5s   (2)
    
    1 创建KubeletConfig CR 时定义cpuManagerPolicy
    2 创建KubeletConfig CR 时定义cpuManagerReconcilePeriod
  8. 运行以下命令创建一个项目:

    $ oc new-project <project_name>
  9. 创建一个请求一个或多个核心的 Pod。限制和请求都必须将其 CPU 值设置为整数。这就是将专用于此 Pod 的核心数。

    # cat cpumanager-pod.yaml
    示例输出
    apiVersion: v1
    kind: Pod
    metadata:
      generateName: cpumanager-
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: cpumanager
        image: gcr.io/google_containers/pause:3.2
        resources:
          requests:
            cpu: 1
            memory: "1G"
          limits:
            cpu: 1
            memory: "1G"
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: [ALL]
      nodeSelector:
        cpumanager: "true"
  10. 创建 Pod

    # oc create -f cpumanager-pod.yaml
验证
  1. 运行以下命令验证 Pod 是否已调度到您添加标签的节点:

    # oc describe pod cpumanager
    示例输出
    Name:               cpumanager-6cqz7
    Namespace:          default
    Priority:           0
    PriorityClassName:  <none>
    Node:  perf-node.example.com/xxx.xx.xx.xxx
    ...
     Limits:
          cpu:     1
          memory:  1G
        Requests:
          cpu:        1
          memory:     1G
    ...
    QoS Class:       Guaranteed
    Node-Selectors:  cpumanager=true
  2. 运行以下命令验证 CPU 是否已独占分配给 Pod:

    # oc describe node --selector='cpumanager=true' | grep -i cpumanager- -B2
    示例输出
    NAMESPACE    NAME                CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
    cpuman       cpumanager-mlrrz    1 (28%)       1 (28%)     1G (13%)         1G (13%)       27m
  3. 验证cgroups是否已正确设置。运行以下命令获取pause进程的进程 ID (PID):

    # oc debug node/perf-node.example.com
    sh-4.2# systemctl status | grep -B5 pause

    如果输出返回多个 pause 进程条目,则必须识别正确的 pause 进程。

    示例输出
    # ├─init.scope
    │ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 17
    └─kubepods.slice
      ├─kubepods-pod69c01f8e_6b74_11e9_ac0f_0a2b62178a22.slice
      │ ├─crio-b5437308f1a574c542bdf08563b865c0345c8f8c0b0a655612c.scope
      │ └─32706 /pause
  4. 运行以下命令验证服务质量 (QoS) 层级为Guaranteed的 Pod 是否位于kubepods.slice子目录中:

    # cd /sys/fs/cgroup/kubepods.slice/kubepods-pod69c01f8e_6b74_11e9_ac0f_0a2b62178a22.slice/crio-b5437308f1ad1a7db0574c542bdf08563b865c0345c86e9585f8c0b0a655612c.scope
    # for i in `ls cpuset.cpus cgroup.procs` ; do echo -n "$i "; cat $i ; done

    其他 QoS 层级的 Pod 位于父kubepods的子cgroups中。

    示例输出
    cpuset.cpus 1
    tasks 32706
  5. 运行以下命令检查任务的允许 CPU 列表:

    # grep ^Cpus_allowed_list /proc/32706/status
    示例输出
     Cpus_allowed_list:    1
  6. 验证系统上的另一个 Pod 是否无法在为GuaranteedPod 分配的核心上运行。例如,要验证besteffortQoS 层级中的 Pod,请运行以下命令:

    # cat /sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podc494a073_6b77_11e9_98c0_06bba5c387ea.slice/crio-c56982f57b75a2420947f0afc6cafe7534c5734efc34157525fa9abbf99e3849.scope/cpuset.cpus
    # oc describe node perf-node.example.com
    示例输出
    ...
    Capacity:
     attachable-volumes-aws-ebs:  39
     cpu:                         2
     ephemeral-storage:           124768236Ki
     hugepages-1Gi:               0
     hugepages-2Mi:               0
     memory:                      8162900Ki
     pods:                        250
    Allocatable:
     attachable-volumes-aws-ebs:  39
     cpu:                         1500m
     ephemeral-storage:           124768236Ki
     hugepages-1Gi:               0
     hugepages-2Mi:               0
     memory:                      7548500Ki
     pods:                        250
    -------                               ----                           ------------  ----------  ---------------  -------------  ---
      default                                 cpumanager-6cqz7               1 (66%)       1 (66%)     1G (12%)         1G (12%)       29m
    
    Allocated resources:
      (Total limits may be over 100 percent, i.e., overcommitted.)
      Resource                    Requests          Limits
      --------                    --------          ------
      cpu                         1440m (96%)       1 (66%)

    此虚拟机有两个 CPU 核心。system-reserved 设置预留了 500 毫核心,这意味着从节点的总容量中减去半个核心来计算 Node Allocatable 量。您可以看到 Allocatable CPU 为 1500 毫核心。这意味着您可以运行一个 CPU Manager Pod,因为每个 Pod 都将占用一个完整的核心。一个完整的核心相当于 1000 毫核心。如果您尝试调度第二个 Pod,系统会接受该 Pod,但它永远不会被调度。

    NAME                    READY   STATUS    RESTARTS   AGE
    cpumanager-6cqz7        1/1     Running   0          33m
    cpumanager-7qc2t        0/1     Pending   0          11s

拓扑管理器策略

拓扑管理器通过收集来自提示提供程序(例如 CPU 管理器和设备管理器)的拓扑提示,并使用收集到的提示来对齐Pod资源,从而对齐所有服务质量 (QoS) 类别的Pod资源。

拓扑管理器支持四种分配策略,您可以在名为 cpumanager-enabledKubeletConfig 自定义资源 (CR) 中分配这些策略。

none 策略

这是默认策略,不执行任何拓扑对齐。

best-effort 策略

对于具有 best-effort 拓扑管理策略的 Pod 中的每个容器,kubelet 会调用每个提示提供程序来发现其资源可用性。使用此信息,拓扑管理器会存储该容器的首选 NUMA 节点亲和性。如果亲和性不是首选,拓扑管理器会存储此信息并将 Pod 接纳到节点。

restricted 策略

对于具有 restricted 拓扑管理策略的 Pod 中的每个容器,kubelet 会调用每个提示提供程序来发现其资源可用性。使用此信息,拓扑管理器会存储该容器的首选 NUMA 节点亲和性。如果亲和性不是首选,拓扑管理器会拒绝该 Pod 加入节点,导致 Pod 处于Terminated状态,并出现 Pod 接纳失败。

single-numa-node 策略

对于具有 single-numa-node 拓扑管理策略的 Pod 中的每个容器,kubelet 会调用每个提示提供程序来发现其资源可用性。使用此信息,拓扑管理器会确定单 NUMA 节点亲和性是否可行。如果可行,则 Pod 会被接纳到节点。如果单 NUMA 节点亲和性不可行,拓扑管理器会拒绝该 Pod 加入节点。这会导致 Pod 处于 Terminated 状态,并出现 Pod 接纳失败。

设置拓扑管理器

要使用拓扑管理器,必须在名为 cpumanager-enabledKubeletConfig 自定义资源 (CR) 中配置分配策略。如果您已设置 CPU 管理器,则此文件可能存在。如果文件不存在,您可以创建该文件。

先决条件
  • 将 CPU 管理器策略配置为static

步骤

激活拓扑管理器

  1. 在自定义资源中配置拓扑管理器分配策略。

    $ oc edit KubeletConfig cpumanager-enabled
    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: cpumanager-enabled
    spec:
      machineConfigPoolSelector:
        matchLabels:
          custom-kubelet: cpumanager-enabled
      kubeletConfig:
         cpuManagerPolicy: static (1)
         cpuManagerReconcilePeriod: 5s
         topologyManagerPolicy: single-numa-node (2)
    1 此参数必须为static,其中s为小写。
    2 指定您选择的拓扑管理器分配策略。此处,策略为single-numa-node。可接受的值为:defaultbest-effortrestrictedsingle-numa-node

Pod 与拓扑管理器策略的交互

以下示例Pod规范有助于说明 Pod 与拓扑管理器的交互。

以下 Pod 在BestEffort QoS 类别中运行,因为未指定任何资源请求或限制。

spec:
  containers:
  - name: nginx
    image: nginx

下一个 Pod 在Burstable QoS 类别中运行,因为请求小于限制。

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

如果选择的策略不是none,则拓扑管理器不会考虑任何这些Pod规范。

以下最后一个示例 Pod 在 Guaranteed QoS 类别中运行,因为请求等于限制。

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
        example.com/device: "1"
      requests:
        memory: "200Mi"
        cpu: "2"
        example.com/device: "1"

拓扑管理器将考虑此 Pod。拓扑管理器将咨询提示提供程序(即 CPU 管理器和设备管理器)以获取 Pod 的拓扑提示。

拓扑管理器将使用此信息来存储此容器的最佳拓扑。在此 Pod 的情况下,CPU 管理器和设备管理器将在资源分配阶段使用此存储的信息。