# Using Node Affinity via API

NVIDIA Run:ai leverages the Kubernetes' Node Affinity feature to allow administrators and researchers more control over where workloads are scheduled. This guide explains how NVIDIA Run:ai integrates with and supports the standard Kubernetes Node Affinity API, both directly in workload specifications and through administrative policies. For more details, refer to the official [Kubernetes documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity).

## Functionality

You can use the `nodeAffinity` field within your workload specifications (`spec.nodeAffinityRequired`) to define scheduling constraints based on node labels.

When a workload with a node affinity specification is submitted, the [NVIDIA Run:ai Scheduler](/self-hosted/platform-management/runai-scheduler/scheduling/concepts-and-principles.md) evaluates these constraints alongside other scheduling factors such as resource availability and fairness policies.

{% hint style="info" %}
**Note**

Preferred node affinity is not supported.
{% endhint %}

## Supported Features

* **nodeAffinityRequired** (`requiredDuringSchedulingIgnoredDuringExecution`) - Define hard requirements for node selection. Pods are scheduled only onto nodes that meet these requirements
* **Node selector terms** - Use `nodeSelectorTerms` with `matchExpressions` to specify label-based rules.
* **Operators** - Supported operators in `matchExpressions` include: `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, and `Lt`.

```bash
nodeAffinityRequired	<Object>
  nodeSelectorTerms	<[]Object>
    matchExpressions	<[]Object>
      key	    <string>
      operator	<enum> (In, NotIn, Exists, DoesNotExist, Gt, Lt)
      values	<[]string>
```

## Setting Node Affinity in Workload Submissions

When submitting a workload, include the `nodeAffinityRequired` field in the API body. This field should describe the required node affinity rule, similar to Kubernetes’ `nodeAffinity` under `requiredDuringSchedulingIgnoredDuringExecution`.

**Example:**

```bash
curl -L 'https://<COMPANY-URL>/api/v1/workloads/workspaces' \ 
-H 'Authorization: Bearer <API-TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
      "name": "workload-name", 
      "projectId": "<PROJECT-ID>", 
      "clusterId": "<CLUSTER-UUID>", 
      "spec": {
        "nodeAffinityRequired": {
          "nodeSelectorTerms": [
            {
              "matchExpressions": [
                {
                  "key": "run.ai/type",
                  "operator": "In",
                  "values": ["training", "inference"]
                }
              ]
            }
          ]
        }
      }
    }'
```

## Viewing Node Affinity in Workloads

`nodeAffinity` is dynamically generated by combining user input with system-level scheduling requirements. The final, effective affinity expression is a result of several components:

* User-defined affinity - The initial rules you provide for the workload
* Platform features - System-generated rules for features such as node pools and Multi-Node NVLink (MNNVL)
* Scheduling policies - Additional constraints applied by the NVIDIA Run:ai Scheduler

As a result, the affinity expression returned by the `GET workloads/{workloadId}/pods` endpoint reflects this final merged configuration, not only your original input.

**Example:**

A user submits a workload excluding nodes `runai-cluster-system-0-0` and `runai-cluster-system-0-1`:

```bash
"nodeAffinityRequired": {
        "nodeSelectorTerms": [
          {
            "matchExpressions": [
              {
                "key": "kubernetes.io/hostname",
                "operator": "NotIn",
                "values": [
                    "runai-cluster-system-0-0",
                    "runai-cluster-system-0-1"
                ]
              }
            ]
          }
       ]
     }
```

The project also has quotas on two node pools: `pool-a` and `pool-b`. The merged affinity expression returned by the API reflects both the user-defined rules and the system-enforced node pool constraints:

```json
{
  "pods": [
    {
      .
      .
      .
      "requestedNodePools": [
          "pool-b",
          "pool-a"
      ],
      "nodeAffinity": {
        "required": {
          "nodeSelectorTerms": [
            {
              "matchExpressions": [
                {
                  "key": "kubernetes.io/hostname",
                  "operator": "NotIn",
                  "values": [
                    "runai-cluster-system-0-0",
                    "runai-cluster-system-0-1"
                  ]
                },
                {
                  "key": "node-pool-label",
                  "operator": "In",
                  "values": [
                    "b"
                  ]
                }
              ]
            },
            {
              "matchExpressions": [
                {
                  "key": "kubernetes.io/hostname",
                  "operator": "NotIn",
                  "values": [
                    "runai-cluster-system-0-0",
                    "runai-cluster-system-0-1"
                  ]
                },
                {
                  "key": "node-pool-label",
                  "operator": "In",
                  "values": [
                    "a" 
                  ]
                }
              ]
            }
          ]
        }
      },
      .
      .
      .
    }
  ]
}
```

## Applying Node Affinity via Policies

Administrators can enforce node affinity [policies](/self-hosted/platform-management/policies/policy-yaml-reference.md) in two ways:

* Can edit - The administrator applies a policy, but users can override it when submitting a workload.
* Can't edit - The administrator applies a policy that can't be overridden by the user.

**Example**:

```bash
defaults:
  nodeAffinityRequired:
      nodeSelectorTerms:
        - matchExpressions:
            - key: app
              operator: In
              values:
                - frontend
                - backend

rules:
  nodeAffinityRequired:
    canEdit: false
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://run-ai-docs.nvidia.com/api/2.25/api-guides/using-node-affinity-via-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
