To deploy high performance workloads with optimal efficiency, use NUMA-aware scheduling. This feature aligns pods with the underlying hardware topology in your OKD cluster, minimizing latency and maximizing resource utilization.
By using the NUMA Resources Operator, you can schedule high-performance workloads in the same NUMA zone. The Operator deploys a node resources exporting agent that reports on available cluster node NUMA resources, and a secondary scheduler that manages the workloads.
To reduce latency in multiprocessor systems, Non-Uniform Memory Access (NUMA) architecture allows CPUs to access local memory faster than remote memory. This design optimizes performance by prioritizing memory resources that are physically closer to the processor.
A CPU with multiple memory controllers can use any available memory across CPU complexes, regardless of where the memory is located. However, this increased flexibility comes at the expense of performance.
NUMA resource topology refers to the physical locations of CPUs, memory, and PCI devices relative to each other in a NUMA zone. In a NUMA architecture, a NUMA zone is a group of CPUs that has its own processors and memory. Colocated resources are said to be in the same NUMA zone, and CPUs in a zone have faster access to the same local memory than CPUs outside of that zone.
A CPU processing a workload using memory that is outside its NUMA zone is slower than a workload processed in a single NUMA zone. For I/O-constrained workloads, the network interface on a distant NUMA zone slows down how quickly information can reach the application.
Applications can achieve better performance by containing data and processing within the same NUMA zone. For high-performance workloads and applications, such as telecommunications workloads, the cluster must process pod workloads in a single NUMA zone so that the workload can operate to specification.
To process latency-sensitive or high-performance workloads efficiently, use NUMA-aware scheduling. This feature aligns cluster compute resources, such as CPUs, memory, and devices, in the same NUMA zone, optimizing resource efficiency and improving pod density per compute node.
By integrating the performance profile of the Node Tuning Operator with NUMA-aware scheduling, you can further configure CPU affinity to optimize performance for latency-sensitive workloads.
The default OKD pod scheduler scheduling logic considers the available resources of the entire compute node, not individual NUMA zones. If the most restrictive resource alignment is requested in the kubelet topology manager, error conditions can occur when admitting the pod to a node.
Conversely, if the most restrictive resource alignment is not requested, the pod can be admitted to the node without proper resource alignment, leading to worse or unpredictable performance. For example, runaway pod creation with Topology Affinity Error statuses can occur when the pod scheduler makes suboptimal scheduling decisions for guaranteed pod workloads without knowing if the pod’s requested resources are available. Scheduling mismatch decisions can cause indefinite pod startup delays. Also, depending on the cluster state and resource allocation, poor pod scheduling decisions can cause extra load on the cluster because of failed startup attempts.
The NUMA Resources Operator deploys a custom NUMA resources secondary scheduler and other resources to mitigate against the shortcomings of the default OKD pod scheduler. The following diagram provides a high-level overview of NUMA-aware pod scheduling.
The NodeResourceTopology API describes the available NUMA zone resources in each compute node.
The NUMA-aware secondary scheduler receives information about the available NUMA zones from the NodeResourceTopology API and schedules high-performance workloads on a node where it can be optimally processed.
The node topology exporter exposes the available NUMA zone resources for each compute node to the NodeResourceTopology API. The node topology exporter daemon tracks the resource allocation from the kubelet by using the PodResources API.
The PodResources API is local to each node and exposes the resource topology and available resources to the kubelet.
|
The The |
To optimize the placement of high-performance workloads, the secondary scheduler uses NUMA-aware scoring strategies to select the most suitable compute nodes. This process assigns workloads based on resource availability while allowing local node managers to handle final resource pinning.
When scheduling high-performance workloads, the secondary scheduler determines which compute node is best suited for the task based on its internal NUMA resource distribution. While the scheduler uses NUMA-level data to score and select a compute node, the actual resource pinning within that node is managed by the local Topology Manager and CPU Manager.
The scheduler first selects a suitable compute node based on cluster-wide criteria. For example taints, labels, or resource availability.
After a compute node is selected, the scheduler evaluates its NUMA nodes and applies a scoring strategy to decide which NUMA node will handle the workload.
After a workload is scheduled, the selected NUMA node’s resources are updated to reflect the allocation.
The default strategy applied is the LeastAllocated strategy. This assigns workloads to the NUMA node with the most available resources that is the least utilized NUMA node. The goal of this strategy is to spread workloads across NUMA nodes to reduce contention and avoid hotspots.
The following table summarizes the different strategies and their outcomes:
| Strategy | Description | Outcome |
|---|---|---|
|
Favors compute nodes that contain NUMA zones with the most available resources. |
Distributes workloads across the cluster to nodes with the highest available headroom. |
|
Favors compute nodes where the requested resources fit into NUMA zones that are already highly utilized. |
Consolidates workloads on already utilized nodes, potentially leaving other nodes idle. |
|
Favors compute nodes with the most balanced CPU and memory usage across NUMA zones. |
Prevents skewed usage patterns where one resource type, such as CPU, is exhausted while another, such as memory, remains idle. |
The LeastAllocated is the default strategy. This strategy assigns workloads to the NUMA node with the most available resources, minimizing resource contention and spreading workloads across NUMA nodes. This reduces hotspots and ensures sufficient headroom for high-priority tasks. Assume a compute node has two NUMA nodes, and the workload requires 4 vCPUs and 8 GB of memory:
| NUMA node | Total CPUs | Used CPUs | Total memory (GB) | Used memory (GB) | Available resources |
|---|---|---|---|---|---|
NUMA 1 |
16 |
12 |
64 |
56 |
4 CPUs, 8 GB memory |
NUMA 2 |
16 |
6 |
64 |
24 |
10 CPUs, 40 GB memory |
Because NUMA 2 has more available resources compared to NUMA 1, the workload is assigned to NUMA 2.
The MostAllocated strategy consolidates workloads by assigning them to the NUMA node with the least available resources, which is the most utilized NUMA node. This approach helps free other NUMA nodes for energy efficiency or critical workloads requiring full isolation. This example uses the "Example initial NUMA nodes state" values listed in the LeastAllocated section.
The workload again requires 4 vCPUs and 8 GB memory. NUMA 1 has fewer available resources compared to NUMA 2, so the scheduler assigns the workload to NUMA 1, further utilizing its resources while leaving NUMA 2 idle or minimally loaded.
The BalancedAllocation strategy assigns workloads to the NUMA node with the most balanced resource utilization across CPU and memory. The goal is to prevent imbalanced usage, such as high CPU utilization with underutilized memory. Assume a compute node has the following NUMA node states:
| NUMA node | CPU usage | Memory usage | BalancedAllocation score |
|---|---|---|---|
NUMA 1 |
60% |
55% |
High (more balanced) |
NUMA 2 |
80% |
20% |
Low (less balanced) |
NUMA 1 has a more balanced CPU and memory utilization compared to NUMA 2 and therefore, with the BalancedAllocation strategy in place, the workload is assigned to NUMA 1.
NUMA Resources Operator deploys resources that allow you to schedule NUMA-aware workloads and deployments. You can install the NUMA Resources Operator using the OKD CLI or the web console.
To enable NUMA-aware scheduling for high-performance workloads, install the NUMA Resources Operator by using the OpenShift CLI (oc). As a cluster administrator, you can deploy the Operator efficiently without using the web console.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Create a namespace for the NUMA Resources Operator:
Save the following YAML in the nro-namespace.yaml file:
apiVersion: v1
kind: Namespace
metadata:
name: openshift-numaresources
# ...
Create the Namespace CR by running the following command:
$ oc create -f nro-namespace.yaml
Create the Operator group for the NUMA Resources Operator:
Save the following YAML in the nro-operatorgroup.yaml file:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: numaresources-operator
namespace: openshift-numaresources
spec:
targetNamespaces:
- openshift-numaresources
# ...
Create the OperatorGroup CR by running the following command:
$ oc create -f nro-operatorgroup.yaml
Create the subscription for the NUMA Resources Operator:
Save the following YAML in the nro-sub.yaml file:
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: numaresources-operator
namespace: openshift-numaresources
spec:
channel: "4.16"
name: numaresources-operator
source: redhat-operators
sourceNamespace: openshift-marketplace
# ...
Create the Subscription CR by running the following command:
$ oc create -f nro-sub.yaml
Verify that the installation succeeded by inspecting the CSV resource in the openshift-numaresources namespace. Run the following command:
$ oc get csv -n openshift-numaresources
NAME DISPLAY VERSION REPLACES PHASE
numaresources-operator.v4.16.2 numaresources-operator 4.16.2 Succeeded
To enable NUMA-aware scheduling for high-performance workloads, install the NUMA Resources Operator by using the web console. As a cluster administrator, you can deploy the Operator through the graphical interface.
Create a namespace for the NUMA Resources Operator:
In the OKD web console, click Administration → Namespaces.
Click Create Namespace, enter openshift-numaresources in the Name field, and then click Create.
Install the NUMA Resources Operator:
In the OKD web console, click Operators → OperatorHub.
Choose numaresources-operator from the list of available Operators, and then click Install.
In the Installed Namespaces field, select the openshift-numaresources namespace, and then click Install.
Optional: Verify that the NUMA Resources Operator installed successfully:
Switch to the Operators → Installed Operators page.
Ensure that NUMA Resources Operator is listed in the openshift-numaresources namespace with a Status of InstallSucceeded.
|
During installation an Operator might display a Failed status. If the installation later succeeds with an InstallSucceeded message, you can ignore the Failed message. |
If the Operator does not appear as installed, to troubleshoot further:
Go to the Operators → Installed Operators page and inspect the Operator Subscriptions and Install Plans tabs for any failure or errors under Status.
Go to the Workloads → Pods page and check the logs for pods in the default project.
To process latency-sensitive and high-performance workloads efficiently, configure your OKD cluster for NUMA-aware scheduling. This process aligns pods with specific NUMA zones to minimize network delays and maximize compute resource utilization.
Clusters running latency-sensitive workloads typically feature performance profiles that help to minimize workload latency and optimize performance. The NUMA-aware scheduler deploys workloads based on available node NUMA resources and with respect to any performance profile settings applied to the node. The combination of NUMA-aware deployments, and the performance profile of the workload, ensures that workloads are scheduled in a way that maximizes performance.
For the NUMA Resources Operator to be fully operational, you must deploy the NUMAResourcesOperator custom resource and the NUMA-aware secondary pod scheduler.
After you have installed the NUMA Resources Operator, you can create the NUMAResourcesOperator custom resource (CR). This CR instructs the NUMA Resources Operator to install all the cluster infrastructure that is needed to support the NUMA-aware scheduler, including daemon sets and APIs.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Installed the NUMA Resources Operator.
Create the NUMAResourcesOperator custom resource:
Save the following minimal required YAML file example as nrop.yaml:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesOperator
metadata:
name: numaresourcesoperator
spec:
nodeGroups:
- machineConfigPoolSelector:
matchLabels:
pools.operator.machineconfiguration.openshift.io/worker: ""
# ...
pools.operator.machineconfiguration.openshift.io/worker: Specifies a value that must match the MachineConfigPool resource that you want to configure the NUMA Resources Operator on. For example, you might have created a MachineConfigPool resource named worker-cnf that designates a set of nodes expected to run telecommunications workloads. Each NodeGroup must match exactly one MachineConfigPool. Configurations where NodeGroup matches more than one MachineConfigPool are not supported.
Create the NUMAResourcesOperator CR by running the following command:
$ oc create -f nrop.yaml
|
Creating the |
Optional: To enable NUMA-aware scheduling for multiple machine config pools (MCPs), define a separate NodeGroup for each pool. For example, define three NodeGroups for worker-cnf, worker-ht, and worker-other, in the NUMAResourcesOperator CR as shown in the following example:
NUMAResourcesOperator CR with multiple NodeGroupsapiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesOperator
metadata:
name: numaresourcesoperator
spec:
logLevel: Normal
nodeGroups:
- machineConfigPoolSelector:
matchLabels:
machineconfiguration.openshift.io/role: worker-ht
- machineConfigPoolSelector:
matchLabels:
machineconfiguration.openshift.io/role: worker-cnf
- machineConfigPoolSelector:
matchLabels:
machineconfiguration.openshift.io/role: worker-other
# ...
Verify that the NUMA Resources Operator deployed successfully by running the following command:
$ oc get numaresourcesoperators.nodetopology.openshift.io
NAME AGE
numaresourcesoperator 27s
After a few minutes, run the following command to verify that the required resources deployed successfully:
$ oc get all -n openshift-numaresources
NAME READY STATUS RESTARTS AGE
pod/numaresources-controller-manager-7d9d84c58d-qk2mr 1/1 Running 0 12m
pod/numaresourcesoperator-worker-7d96r 2/2 Running 0 97s
pod/numaresourcesoperator-worker-crsht 2/2 Running 0 97s
pod/numaresourcesoperator-worker-jp9mw 2/2 Running 0 97s
To optimize the placement of high-performance workloads, deploy the NUMA-aware secondary pod scheduler. This component aligns pods with specific NUMA zones to ensure efficient resource utilization in your cluster.
Create the NUMAResourcesScheduler custom resource that deploys the NUMA-aware custom pod scheduler:
Save the following minimal required YAML in the nro-scheduler.yaml file:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesScheduler
metadata:
name: numaresourcesscheduler
spec:
imageSpec: "registry.redhat.io/openshift4/noderesourcetopology-scheduler-rhel9:v4.16"
# ...
spec.imageSpec: In a disconnected environment, make sure to configure the resolution of this image by either:
Create an ImageTagMirrorSet custom resource (CR). For more information, see "Configuring image registry repository mirroring" in the "Additional resources" section.
Set the URL to the disconnected registry.
Create the NUMAResourcesScheduler CR by running the following command:
$ oc create -f nro-scheduler.yaml
After a few seconds, run the following command to confirm the successful deployment of the required resources:
$ oc get all -n openshift-numaresources
NAME READY STATUS RESTARTS AGE
pod/numaresources-controller-manager-7d9d84c58d-qk2mr 1/1 Running 0 12m
pod/numaresourcesoperator-worker-7d96r 2/2 Running 0 97s
pod/numaresourcesoperator-worker-crsht 2/2 Running 0 97s
pod/numaresourcesoperator-worker-jp9mw 2/2 Running 0 97s
pod/secondary-scheduler-847cb74f84-9whlm 1/1 Running 0 10m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/numaresourcesoperator-worker 3 3 3 3 3 node-role.kubernetes.io/worker= 98s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/numaresources-controller-manager 1/1 1 1 12m
deployment.apps/secondary-scheduler 1/1 1 1 10m
NAME DESIRED CURRENT READY AGE
replicaset.apps/numaresources-controller-manager-7d9d84c58d 1 1 1 12m
replicaset.apps/secondary-scheduler-847cb74f84 1 1 1 10m
To enable the NUMA Resources Operator, configure a single NUMA node policy on your cluster. You can implement this policy by creating a performance profile or by configuring a KubeletConfig custom resource (CR).
|
The preferred way to configure a single NUMA node policy is to apply a performance profile. You can use the Performance Profile Creator (PPC) tool to create the performance profile. If a performance profile is created on the cluster, the PPC tool automatically creates other tuning components like |
For more information about creating a performance profile, see "About the Performance Profile Creator" in the "Additional resources" section.
Reference an example YAML to understand how to use the performance profile creator (PPC) tool to create a performance profile.
apiVersion: performance.openshift.io/v2
kind: PerformanceProfile
metadata:
name: performance
spec:
cpu:
isolated: "3"
reserved: 0-2
machineConfigPoolSelector:
pools.operator.machineconfiguration.openshift.io/worker: ""
nodeSelector:
node-role.kubernetes.io/worker: ""
numa:
topologyPolicy: single-numa-node
realTimeKernel:
enabled: true
workloadHints:
highPowerConsumption: true
perPodPowerManagement: false
realTime: true
spec.pools.operator.machineconfiguration.openshift.io/worker:: Specifies the value that must match the MachineConfigPool value that you want to configure the NUMA Resources Operator on. For example, you might create a MachineConfigPool object named worker-cnf that designates a set of nodes that run telecommunications workloads. The value for MachineConfigPool must match the machineConfigPoolSelector value in the NUMAResourcesOperator CR that you configure later in "Creating the NUMAResourcesOperator custom resource".
spec.numa.topologyPolicy:: Specifies that the topologyPolicy field is set to single-numa-node by setting the topology-manager-policy argument to single-numa-node when you run the PPC tool.
|
For hosted control plane clusters, the |
To configure a single NUMA node policy, create and apply a KubeletConfig custom resource (CR). While applying a performance profile is recommended, you can use the alternative method to manually manage the configuration on your cluster.
Create the KubeletConfig custom resource (CR) that configures the pod admittance policy for the machine profile:
Save the following YAML in the nro-kubeletconfig.yaml file:
apiVersion: machineconfiguration.openshift.io/v1
kind: KubeletConfig
metadata:
name: worker-tuning
spec:
machineConfigPoolSelector:
matchLabels:
pools.operator.machineconfiguration.openshift.io/worker: ""
kubeletConfig:
cpuManagerPolicy: "static"
cpuManagerReconcilePeriod: "5s"
reservedSystemCPUs: "0,1"
memoryManagerPolicy: "Static"
evictionHard:
memory.available: "100Mi"
kubeReserved:
memory: "512Mi"
reservedMemory:
- numaNode: 0
limits:
memory: "1124Mi"
systemReserved:
memory: "512Mi"
topologyManagerPolicy: "single-numa-node"
where:
spec.machineConfigPoolSelector.matchLabels.pools.operator.machineconfiguration.openshift.io/workerSpecifies that this label matches the machineConfigPoolSelector setting in the NUMAResourcesOperator CR that you configure later in "Creating the NUMAResourcesOperator custom resource".
spec.kubeletConfig.cpuManagerPolicySpecifies the static value. You must use a lowercase s.
spec.kubeletConfig.reservedSystemCPUsAdjust the field based on the CPU on your nodes.
spec.kubeletConfig.memoryManagerPolicySpecifies Static. You must use an uppercase S.
spec.kubeletConfig.topologyManagerPolicySpecifies the value as single-numa-node.
|
For hosted control plane clusters, the |
Create the KubeletConfig CR by running the following command:
$ oc create -f nro-kubeletconfig.yaml
|
Applying performance profile or |
To schedule workloads with the NUMA-aware scheduler, use deployment CRs that specify the minimum required resources. This ensures your cluster processes the workloads efficiently.
Before you schedule workloads with the NUMA-aware scheduler, ensure that you previouslu installed the topo-aware-scheduler, you applied the NUMAResourcesOperator and NUMAResourcesScheduler CRs, and that your cluster has a matching performance profile or kubeletconfig.
The example in the procedure uses NUMA-aware scheduling for a sample workload.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Get the name of the NUMA-aware scheduler that is deployed in the cluster by running the following command:
$ oc get numaresourcesschedulers.nodetopology.openshift.io numaresourcesscheduler -o json | jq '.status.schedulerName'
"topo-aware-scheduler"
Create a Deployment CR that uses scheduler named topo-aware-scheduler, for example:
Save the following YAML in the nro-deployment.yaml file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: numa-deployment-1
namespace: openshift-numaresources
spec:
replicas: 1
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
schedulerName: topo-aware-scheduler
containers:
- name: ctnr
image: quay.io/openshifttest/hello-openshift:openshift
imagePullPolicy: IfNotPresent
resources:
limits:
memory: "100Mi"
cpu: "10"
requests:
memory: "100Mi"
cpu: "10"
- name: ctnr2
image: registry.access.redhat.com/rhel:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c"]
args: [ "while true; do sleep 1h; done;" ]
resources:
limits:
memory: "100Mi"
cpu: "8"
requests:
memory: "100Mi"
cpu: "8"
spec.schedulerName: Specifies the scheduler name that must match the name of the NUMA-aware scheduler that is deployed in your cluster, such as topo-aware-scheduler.
Create the Deployment CR by running the following command:
$ oc create -f nro-deployment.yaml
Verify that the deployment was successful:
$ oc get pods -n openshift-numaresources
NAME READY STATUS RESTARTS AGE
numa-deployment-1-6c4f5bdb84-wgn6g 2/2 Running 0 5m2s
numaresources-controller-manager-7d9d84c58d-4v65j 1/1 Running 0 18m
numaresourcesoperator-worker-7d96r 2/2 Running 4 43m
numaresourcesoperator-worker-crsht 2/2 Running 2 43m
numaresourcesoperator-worker-jp9mw 2/2 Running 2 43m
secondary-scheduler-847cb74f84-fpncj 1/1 Running 0 18m
Verify that the topo-aware-scheduler is scheduling the deployed pod by running the following command:
$ oc describe pod numa-deployment-1-6c4f5bdb84-wgn6g -n openshift-numaresources
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m45s topo-aware-scheduler Successfully assigned openshift-numaresources/numa-deployment-1-6c4f5bdb84-wgn6g to worker-1
|
Deployments that request more resources than is available for scheduling will fail with a |
Verify that the expected allocated resources are listed for the node.
Identify the node that is running the deployment pod by running the following command:
$ oc get pods -n openshift-numaresources -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
numa-deployment-1-6c4f5bdb84-wgn6g 0/2 Running 0 82m 10.128.2.50 worker-1 <none> <none>
Run the following command with the name of that node that is running the deployment pod.
$ oc describe noderesourcetopologies.topology.node.k8s.io worker-1
...
Zones:
Costs:
Name: node-0
Value: 10
Name: node-1
Value: 21
Name: node-0
Resources:
Allocatable: 39
Available: 21
Capacity: 40
Name: cpu
Allocatable: 6442450944
Available: 6442450944
Capacity: 6442450944
Name: hugepages-1Gi
Allocatable: 134217728
Available: 134217728
Capacity: 134217728
Name: hugepages-2Mi
Allocatable: 262415904768
Available: 262206189568
Capacity: 270146007040
Name: memory
Type: Node
Resources.Available: Specifies the Available capacity that is reduced because of the resources that have been allocated to the guaranteed pod. Resources consumed by guaranteed pods are subtracted from the available node resources listed under noderesourcetopologies.topology.node.k8s.io.
Resource allocations for pods with a Best-effort or Burstable quality of service (qosClass) are not reflected in the NUMA node resources under noderesourcetopologies.topology.node.k8s.io. If a pod’s consumed resources are not reflected in the node resource calculation, verify that the pod has qosClass of Guaranteed and the CPU request is an integer value, not a decimal value. You can verify the that the pod has a qosClass of Guaranteed by running the following command:
$ oc get pod numa-deployment-1-6c4f5bdb84-wgn6g -n openshift-numaresources -o jsonpath="{ .status.qosClass }"
Guaranteed
As an optional task, you can improve scheduling behavior and troubleshoot suboptimal scheduling decisions by configuring the spec.nodeGroups specification in the NUMAResourcesOperator custom resource (CR). This configuration fine-tunes how daemons poll for available NUMA resources, providing advanced control over your polling operations.
The configuration options are listed as follows:
infoRefreshMode: Determines the trigger condition for polling the kubelet. The NUMA Resources Operator reports the resulting information to the API server.
infoRefreshPeriod: Determines the duration between polling updates.
podsFingerprinting: Determines if point-in-time information for the current set of pods running on a node is exposed in polling updates.
|
The default value for |
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Installed the NUMA Resources Operator.
Configure the spec.nodeGroups specification in your NUMAResourcesOperator CR:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesOperator
metadata:
name: numaresourcesoperator
spec:
nodeGroups:
- config:
infoRefreshMode: Periodic
infoRefreshPeriod: 10s
podsFingerprinting: Enabled
name: worker
# ...
spec.nodeGroups.config.infoRefreshMode:: Valid values are Periodic, Events, PeriodicAndEvents. Use Periodic to poll the kubelet at intervals that you define in infoRefreshPeriod. Use Events to poll the kubelet at every pod lifecycle event. Use PeriodicAndEvents to enable both methods.
spec.nodeGroups.config.infoRefreshPeriod:: Specifies the polling interval for Periodic or PeriodicAndEvents refresh modes. The field is ignored if the refresh mode is Events.
spec.nodeGroups.config.podsFingerprinting:: Valid values are Enabled, Disabled, and EnabledExclusiveResources. Setting to Enabled or EnabledExclusiveResources is a requirement for the cacheResyncPeriod specification in the NUMAResourcesScheduler.
After you deploy the NUMA Resources Operator, verify that the node group configurations were applied by running the following command:
$ oc get numaresop numaresourcesoperator -o json | jq '.status'
...
"config": {
"infoRefreshMode": "Periodic",
"infoRefreshPeriod": "10s",
"podsFingerprinting": "Enabled"
},
"name": "worker"
...
To resolve common problems with NUMA-aware pod scheduling, troubleshoot your cluster configuration. Identifying and fixing these issues ensures that your pods are optimally aligned with underlying hardware for high-performance workloads.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Installed the NUMA Resources Operator and deploy the NUMA-aware secondary scheduler.
Verify that the noderesourcetopologies CRD is deployed in the cluster by running the following command:
$ oc get crd | grep noderesourcetopologies
NAME CREATED AT
noderesourcetopologies.topology.node.k8s.io 2022-01-18T08:28:06Z
Check that the NUMA-aware scheduler name matches the name specified in your NUMA-aware workloads by running the following command:
$ oc get numaresourcesschedulers.nodetopology.openshift.io numaresourcesscheduler -o json | jq '.status.schedulerName'
topo-aware-scheduler
Verify that NUMA-aware schedulable nodes have the noderesourcetopologies CR applied to them. Run the following command:
$ oc get noderesourcetopologies.topology.node.k8s.io
NAME AGE
compute-0.example.com 17h
compute-1.example.com 17h
|
The number of nodes should equal the number of worker nodes that are configured by the machine config pool ( |
Verify the NUMA zone granularity for all schedulable nodes by running the following command:
$ oc get noderesourcetopologies.topology.node.k8s.io -o yaml
apiVersion: v1
items:
- apiVersion: topology.node.k8s.io/v1
kind: NodeResourceTopology
metadata:
annotations:
k8stopoawareschedwg/rte-update: periodic
creationTimestamp: "2022-06-16T08:55:38Z"
generation: 63760
name: worker-0
resourceVersion: "8450223"
uid: 8b77be46-08c0-4074-927b-d49361471590
topologyPolicies:
- SingleNUMANodeContainerLevel
zones:
- costs:
- name: node-0
value: 10
- name: node-1
value: 21
name: node-0
resources:
- allocatable: "38"
available: "38"
capacity: "40"
name: cpu
- allocatable: "134217728"
available: "134217728"
capacity: "134217728"
name: hugepages-2Mi
- allocatable: "262352048128"
available: "262352048128"
capacity: "270107316224"
name: memory
- allocatable: "6442450944"
available: "6442450944"
capacity: "6442450944"
name: hugepages-1Gi
type: Node
- costs:
- name: node-0
value: 21
- name: node-1
value: 10
name: node-1
resources:
- allocatable: "268435456"
available: "268435456"
capacity: "268435456"
name: hugepages-2Mi
- allocatable: "269231067136"
available: "269231067136"
capacity: "270573244416"
name: memory
- allocatable: "40"
available: "40"
capacity: "40"
name: cpu
- allocatable: "1073741824"
available: "1073741824"
capacity: "1073741824"
name: hugepages-1Gi
type: Node
- apiVersion: topology.node.k8s.io/v1
kind: NodeResourceTopology
metadata:
annotations:
k8stopoawareschedwg/rte-update: periodic
creationTimestamp: "2022-06-16T08:55:37Z"
generation: 62061
name: worker-1
resourceVersion: "8450129"
uid: e8659390-6f8d-4e67-9a51-1ea34bba1cc3
topologyPolicies:
- SingleNUMANodeContainerLevel
zones:
- costs:
- name: node-0
value: 10
- name: node-1
value: 21
name: node-0
resources:
- allocatable: "38"
available: "38"
capacity: "40"
name: cpu
- allocatable: "6442450944"
available: "6442450944"
capacity: "6442450944"
name: hugepages-1Gi
- allocatable: "134217728"
available: "134217728"
capacity: "134217728"
name: hugepages-2Mi
- allocatable: "262391033856"
available: "262391033856"
capacity: "270146301952"
name: memory
type: Node
- costs:
- name: node-0
value: 21
- name: node-1
value: 10
name: node-1
resources:
- allocatable: "40"
available: "40"
capacity: "40"
name: cpu
- allocatable: "1073741824"
available: "1073741824"
capacity: "1073741824"
name: hugepages-1Gi
- allocatable: "268435456"
available: "268435456"
capacity: "268435456"
name: hugepages-2Mi
- allocatable: "269192085504"
available: "269192085504"
capacity: "270534262784"
name: memory
type: Node
kind: List
metadata:
resourceVersion: ""
selfLink: ""
# ...
zones: Each stanza under zones describes the resources for a single NUMA zone.
costs.resources: Specifies the current state of the NUMA zone resources. Check that resources listed under items.zones.resources.available correspond to the exclusive NUMA zone resources allocated to each guaranteed pod.
To report more exact resource availability and minimize Topology Affinity Errors, enable the cacheResyncPeriod specification for the NUMA Resources Operator. This configuration monitors pending resources on nodes and synchronizes them in the scheduler cache, though lower intervals increase network load.
The lower the interval, the greater the network load. The cacheResyncPeriod specification is disabled by default.
Installed the OpenShift CLI (oc).
You are logged in as a user with cluster-admin privileges.
Delete the currently running NUMAResourcesScheduler resource:
Get the active NUMAResourcesScheduler by running the following command:
$ oc get NUMAResourcesScheduler
NAME AGE
numaresourcesscheduler 92m
Delete the secondary scheduler resource by running the following command:
$ oc delete NUMAResourcesScheduler numaresourcesscheduler
numaresourcesscheduler.nodetopology.openshift.io "numaresourcesscheduler" deleted
Save the following YAML in the file nro-scheduler-cacheresync.yaml. This example changes the log level to Debug:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesScheduler
metadata:
name: numaresourcesscheduler
spec:
imageSpec: "registry.redhat.io/openshift4/noderesourcetopology-scheduler-container-rhel8:v4.16"
cacheResyncPeriod: "5s"
spec.cacheResyncPeriod: Enter an interval value in seconds for synchronization of the scheduler cache. A value of 5s is typical for most implementations.
Create the updated NUMAResourcesScheduler resource by running the following command:
$ oc create -f nro-scheduler-cacheresync.yaml
numaresourcesscheduler.nodetopology.openshift.io/numaresourcesscheduler created
Check that the NUMA-aware scheduler was successfully deployed:
Run the following command to check that the CRD is created successfully:
$ oc get crd | grep numaresourcesschedulers
NAME CREATED AT
numaresourcesschedulers.nodetopology.openshift.io 2022-02-25T11:57:03Z
Check that the new custom scheduler is available by running the following command:
$ oc get numaresourcesschedulers.nodetopology.openshift.io
NAME AGE
numaresourcesscheduler 3h26m
Check that the logs for the scheduler show the increased log level:
Get the list of pods running in the openshift-numaresources namespace by running the following command:
$ oc get pods -n openshift-numaresources
NAME READY STATUS RESTARTS AGE
numaresources-controller-manager-d87d79587-76mrm 1/1 Running 0 46h
numaresourcesoperator-worker-5wm2k 2/2 Running 0 45h
numaresourcesoperator-worker-pb75c 2/2 Running 0 45h
secondary-scheduler-7976c4d466-qm4sc 1/1 Running 0 21m
Get the logs for the secondary scheduler pod by running the following command:
$ oc logs secondary-scheduler-7976c4d466-qm4sc -n openshift-numaresources
...
I0223 11:04:55.614788 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.Namespace total 11 items received
I0223 11:04:56.609114 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.ReplicationController total 10 items received
I0223 11:05:22.626818 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.StorageClass total 7 items received
I0223 11:05:31.610356 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.PodDisruptionBudget total 7 items received
I0223 11:05:31.713032 1 eventhandlers.go:186] "Add event for scheduled pod" pod="openshift-marketplace/certified-operators-thtvq"
I0223 11:05:53.461016 1 eventhandlers.go:244] "Delete event for scheduled pod" pod="openshift-marketplace/certified-operators-thtvq"
To optimize the processing of high-performance workloads, change the default placement behavior of the NUMA-aware secondary scheduler. With this configuration, you can assign workloads to a specific NUMA node within a compute node instead of relying on default resource availability.
If you want to change where the workloads run, you can add the scoringStrategy setting to the NUMAResourcesScheduler custom resource and set its value to either MostAllocated or BalancedAllocation.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Delete the currently running NUMAResourcesScheduler resource by using the following steps:
Get the active NUMAResourcesScheduler by running the following command:
$ oc get NUMAResourcesScheduler
NAME AGE
numaresourcesscheduler 92m
Delete the secondary scheduler resource by running the following command:
$ oc delete NUMAResourcesScheduler numaresourcesscheduler
numaresourcesscheduler.nodetopology.openshift.io "numaresourcesscheduler" deleted
Save the following YAML in the file nro-scheduler-mostallocated.yaml. This example changes the scoringStrategy to MostAllocated:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesScheduler
metadata:
name: numaresourcesscheduler
spec:
imageSpec: "registry.redhat.io/openshift4/noderesourcetopology-scheduler-container-rhel8:v{product-version}"
scoringStrategy:
type: "MostAllocated"
# ...
spec.imageSpec.scoringStrategy: If the scoringStrategy configuration is omitted, the default of LeastAllocated applies.
Create the updated NUMAResourcesScheduler resource by running the following command:
$ oc create -f nro-scheduler-mostallocated.yaml
numaresourcesscheduler.nodetopology.openshift.io/numaresourcesscheduler created
Check that the NUMA-aware scheduler was successfully deployed by using the following steps:
Run the following command to check that the custom resource definition (CRD) is created successfully:
$ oc get crd | grep numaresourcesschedulers
NAME CREATED AT
numaresourcesschedulers.nodetopology.openshift.io 2022-02-25T11:57:03Z
Check that the new custom scheduler is available by running the following command:
$ oc get numaresourcesschedulers.nodetopology.openshift.io
NAME AGE
numaresourcesscheduler 3h26m
Verify that the ScoringStrategy has been applied correctly by running the following command to check the relevant ConfigMap resource for the scheduler:
$ oc get -n openshift-numaresources cm topo-aware-scheduler-config -o yaml | grep scoring -A 1
scoringStrategy:
type: MostAllocated
To troubleshoot problems with the NUMA-aware scheduler, review the scheduler logs. If necessary, increase the log level in the NUMAResourcesScheduler custom resource (CR) to capture more detailed diagnostic data.
Acceptable values are Normal, Debug, and Trace, with Trace being the most verbose option.
|
To change the log level of the secondary scheduler, delete the running scheduler resource and re-deploy it with the changed log level. The scheduler is unavailable for scheduling new workloads during this downtime. |
Installed the OpenShift CLI (oc).
You are logged in as a user with cluster-admin privileges.
Delete the currently running NUMAResourcesScheduler resource:
Get the active NUMAResourcesScheduler by running the following command:
$ oc get NUMAResourcesScheduler
NAME AGE
numaresourcesscheduler 90m
Delete the secondary scheduler resource by running the following command:
$ oc delete NUMAResourcesScheduler numaresourcesscheduler
numaresourcesscheduler.nodetopology.openshift.io "numaresourcesscheduler" deleted
Save the following YAML in the file nro-scheduler-debug.yaml. This example changes the log level to Debug:
apiVersion: nodetopology.openshift.io/v1
kind: NUMAResourcesScheduler
metadata:
name: numaresourcesscheduler
spec:
imageSpec: "registry.redhat.io/openshift4/noderesourcetopology-scheduler-container-rhel8:v4.16"
logLevel: Debug
# ...
Create the updated Debug logging NUMAResourcesScheduler resource by running the following command:
$ oc create -f nro-scheduler-debug.yaml
numaresourcesscheduler.nodetopology.openshift.io/numaresourcesscheduler created
Check that the NUMA-aware scheduler was successfully deployed:
Run the following command to check that the CRD is created successfully:
$ oc get crd | grep numaresourcesschedulers
NAME CREATED AT
numaresourcesschedulers.nodetopology.openshift.io 2022-02-25T11:57:03Z
Check that the new custom scheduler is available by running the following command:
$ oc get numaresourcesschedulers.nodetopology.openshift.io
NAME AGE
numaresourcesscheduler 3h26m
Check that the logs for the scheduler shows the increased log level:
Get the list of pods running in the openshift-numaresources namespace by running the following command:
$ oc get pods -n openshift-numaresources
NAME READY STATUS RESTARTS AGE
numaresources-controller-manager-d87d79587-76mrm 1/1 Running 0 46h
numaresourcesoperator-worker-5wm2k 2/2 Running 0 45h
numaresourcesoperator-worker-pb75c 2/2 Running 0 45h
secondary-scheduler-7976c4d466-qm4sc 1/1 Running 0 21m
Get the logs for the secondary scheduler pod by running the following command:
$ oc logs secondary-scheduler-7976c4d466-qm4sc -n openshift-numaresources
...
I0223 11:04:55.614788 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.Namespace total 11 items received
I0223 11:04:56.609114 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.ReplicationController total 10 items received
I0223 11:05:22.626818 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.StorageClass total 7 items received
I0223 11:05:31.610356 1 reflector.go:535] k8s.io/client-go/informers/factory.go:134: Watch close - *v1.PodDisruptionBudget total 7 items received
I0223 11:05:31.713032 1 eventhandlers.go:186] "Add event for scheduled pod" pod="openshift-marketplace/certified-operators-thtvq"
I0223 11:05:53.461016 1 eventhandlers.go:244] "Delete event for scheduled pod" pod="openshift-marketplace/certified-operators-thtvq"
To resolve unexpected results in noderesourcetopologies objects, inspect the resource-topology-exporter logs. Reviewing this diagnostic data helps you identify and fix configuration issues within your cluster.
|
Ensure that the NUMA resource topology exporter instances in the cluster are named for nodes they refer to. For example, a compute node with the name |
Install the OpenShift CLI (oc).
Log in as a user with cluster-admin privileges.
Get the daemonsets managed by the NUMA Resources Operator. Each daemonset has a corresponding nodeGroup in the NUMAResourcesOperator CR. Run the following command:
$ oc get numaresourcesoperators.nodetopology.openshift.io numaresourcesoperator -o jsonpath="{.status.daemonsets[0]}"
{"name":"numaresourcesoperator-worker","namespace":"openshift-numaresources"}
Get the label for the daemonset of interest using the value for name from the previous step:
$ oc get ds -n openshift-numaresources numaresourcesoperator-worker -o jsonpath="{.spec.selector.matchLabels}"
{"name":"resource-topology"}
Get the pods using the resource-topology label by running the following command:
$ oc get pods -n openshift-numaresources -l name=resource-topology -o wide
NAME READY STATUS RESTARTS AGE IP NODE
numaresourcesoperator-worker-5wm2k 2/2 Running 0 2d1h 10.135.0.64 compute-0.example.com
numaresourcesoperator-worker-pb75c 2/2 Running 0 2d1h 10.132.2.33 compute-1.example.com
Examine the logs of the resource-topology-exporter container running on the worker pod that corresponds to the node you are troubleshooting. Run the following command:
$ oc logs -n openshift-numaresources -c resource-topology-exporter numaresourcesoperator-worker-pb75c
I0221 13:38:18.334140 1 main.go:206] using sysinfo:
reservedCpus: 0,1
reservedMemory:
"0": 1178599424
I0221 13:38:18.334370 1 main.go:67] === System information ===
I0221 13:38:18.334381 1 sysinfo.go:231] cpus: reserved "0-1"
I0221 13:38:18.334493 1 sysinfo.go:237] cpus: online "0-103"
I0221 13:38:18.546750 1 main.go:72]
cpus: allocatable "2-103"
hugepages-1Gi:
numa cell 0 -> 6
numa cell 1 -> 1
hugepages-2Mi:
numa cell 0 -> 64
numa cell 1 -> 128
memory:
numa cell 0 -> 45758Mi
numa cell 1 -> 48372Mi
To correct a missing config map for the resource topology exporter (RTE), resolve misconfigured settings in your cluster. Fixing this issue ensures the NUMA Resources Operator functions properly when the logs of the RTE daemon set pods indicate missing configurations.
The following example log message indicates a missing configuration:
Info: couldn't find configuration in "/etc/resource-topology-exporter/config.yaml"
The previous log message indicates that the kubeletconfig with the required configuration was not properly applied in the cluster, resulting in a missing RTE configmap. For example, the following cluster is missing a numaresourcesoperator-worker configmap custom resource (CR):
$ oc get configmap
Example output:
NAME DATA AGE
0e2a6bd3.openshift-kni.io 0 6d21h
kube-root-ca.crt 1 6d21h
openshift-service-ca.crt 1 6d21h
topo-aware-scheduler-config 1 6d18h
In a correctly configured cluster, oc get configmap also returns a numaresourcesoperator-worker configmap CR.
Installed the OpenShift CLI (oc).
Logged in as a user with cluster-admin privileges.
Installed the NUMA Resources Operator and deploy the NUMA-aware secondary scheduler.
Compare the values for spec.machineConfigPoolSelector.matchLabels in kubeletconfig and
metadata.labels in the MachineConfigPool (mcp) worker CR using the following commands:
Check the kubeletconfig labels by running the following command:
$ oc get kubeletconfig -o yaml
machineConfigPoolSelector:
matchLabels:
cnf-worker-tuning: enabled
Check the mcp labels by running the following command:
$ oc get mcp worker -o yaml
labels:
machineconfiguration.openshift.io/mco-built-in: ""
pools.operator.machineconfiguration.openshift.io/worker: ""
The cnf-worker-tuning: enabled label is not present in the MachineConfigPool object.
Edit the MachineConfigPool CR to include the missing label, for example:
$ oc edit mcp worker -o yaml
labels:
machineconfiguration.openshift.io/mco-built-in: ""
pools.operator.machineconfiguration.openshift.io/worker: ""
cnf-worker-tuning: enabled
Apply the label changes and wait for the cluster to apply the updated configuration.
Check that the missing numaresourcesoperator-worker configmap CR is applied:
$ oc get configmap
NAME DATA AGE
0e2a6bd3.openshift-kni.io 0 6d21h
kube-root-ca.crt 1 6d21h
numaresourcesoperator-worker 1 5m
openshift-service-ca.crt 1 6d21h
topo-aware-scheduler-config 1 6d18h
You can use the oc adm must-gather CLI command to collect information about your cluster, including features and objects associated with the NUMA Resources Operator.
You have access to the cluster as a user with the cluster-admin role.
You have installed the OpenShift CLI (oc).
To collect NUMA Resources Operator data with must-gather, you must specify the NUMA Resources Operator must-gather image.
$ oc adm must-gather --image=registry.redhat.io/openshift4/numaresources-must-gather-rhel9:v4.16