The nfd engine publishes Topograph topology through
Node Feature Discovery
custom resources instead of writing Kubernetes node labels directly.
It creates:
- one
NodeFeatureper topology node, carrying Topograph topology asspec.features.attributes.topograph.network.elements - one
NodeFeatureGroupper distinct fabric tier, XCLR domain, or XCLR sub-domain value
NFD master evaluates those features and writes matching nodes to
NodeFeatureGroup.status.nodes.
Fabric topology is variable-depth. The engine publishes fabric-tier-N for
every discovered tier, where tier 0 is closest to the node and higher tiers
progress outward; there is no fixed number of fabric attributes or groups.
XCLR domain and optional sub-domain attributes are published separately when
the provider supplies them.
Use engine: nfd only when a downstream component already consumes NFD
NodeFeatureGroup objects. For native Kubernetes scheduling with
podAffinity.topologyKey, use the k8s engine instead.
The NodeFeatureGroupAPI feature gate is disabled by default in NFD. It has
been Alpha since NFD v0.16 and must be enabled explicitly before using this
engine. See the upstream
feature-gate reference
for its current status.
The following example limits the NFD worker to nodes labeled
nfd-enabled=true. Label each intended worker node first:
kubectl label node <node-name> nfd-enabled=trueThen install NFD with the NodeFeatureGroupAPI feature gate enabled:
helm repo add nfd https://kubernetes-sigs.github.io/node-feature-discovery/charts
helm repo update
helm install nfd nfd/node-feature-discovery \
--namespace node-feature-discovery \
--create-namespace \
--set-string worker.nodeSelector.nfd-enabled=true \
--set featureGates.NodeFeatureGroupAPI=trueOmit worker.nodeSelector.nfd-enabled if the NFD worker should run on all
eligible nodes.
provider:
name: infiniband-k8s
engine:
name: nfd
params:
nodeSelector:
nvidia.com/gpu.present: "true"
cleanup: true
kubeClient:
qps: 50
burst: 100
nfdNamespace: node-feature-discoveryParameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
nodeSelector |
No | all nodes | Limits the Kubernetes nodes used as provider input. Same meaning as the k8s engine selector. |
cleanup |
No | true |
Deletes stale Topograph-managed NodeFeature and NodeFeatureGroup objects that are no longer present in the generated topology. If generation produces no objects, the engine returns an error and preserves the existing topology. |
nfdNamespace is a deployment-level Helm value, not an engine request
parameter. It must be the namespace where NFD master runs because NFD updates
NodeFeatureGroup.status there. The Helm value defaults to
node-feature-discovery.
When rbac.create is enabled, the chart creates a Role and RoleBinding in
that namespace and configures the Topograph deployment with the same value
through NFD_NAMESPACE. Outside Helm, set NFD_NAMESPACE on the Topograph
process. The NFD engine returns an error if the variable is unset or blank.
Topology requests cannot select an NFD namespace; the deployment environment is authoritative.
The NFD engine uses a typed Kubernetes client to list Nodes and a dynamic client
to reconcile NodeFeature and NodeFeatureGroup objects. Helm configures their
shared token-bucket limiter through kubeClient.qps and kubeClient.burst,
which become KUBE_QPS and KUBE_BURST in the Topograph deployment. The
configured QPS is the aggregate request rate rather than a separate allowance
for each client. If only QPS or burst is configured, the other value uses the
client-go default. Without either setting, each client retains its client-go
default limiter. Outside Helm, set the environment variables directly.
For a node on a three-tier fabric, the engine writes a NodeFeature like:
apiVersion: nfd.k8s-sigs.io/v1alpha1
kind: NodeFeature
metadata:
name: topograph-node-node-a-...
namespace: node-feature-discovery
labels:
nfd.node.kubernetes.io/node-name: node-a
app.kubernetes.io/managed-by: topograph
topograph.nvidia.com/engine: nfd
spec:
features:
attributes:
system.name:
elements:
nodename: node-a
topograph.network:
elements:
xclr-domain: nvl3
xclr-sub-domain: nvl3.rack01
fabric-tier-0: leaf-12
fabric-tier-1: spine-2
fabric-tier-2: core-1For each distinct value, it writes a matching NodeFeatureGroup:
apiVersion: nfd.k8s-sigs.io/v1alpha1
kind: NodeFeatureGroup
metadata:
name: topograph-fabric-tier-0-leaf-12-...
namespace: node-feature-discovery
labels:
app.kubernetes.io/managed-by: topograph
topograph.nvidia.com/engine: nfd
topograph.nvidia.com/group-type: fabric-tier-0
annotations:
topograph.nvidia.com/label-key: network.topology.nvidia.com/tier-0
topograph.nvidia.com/label-value: leaf-12
spec:
featureGroupRules:
- name: fabric-tier-0 equals leaf-12
matchFeatures:
- feature: topograph.network
matchExpressions:
fabric-tier-0:
op: In
value: ["leaf-12"]Topograph includes system.name.elements.nodename so NFD can populate group
membership even when an NFD worker does not run on the node, as with simulated
KWOK nodes. Topograph does not write status.nodes; NFD owns status updates.
If a Kubernetes node already has nvidia.com/gpu.clique, the engine uses that
label's value as the authoritative xclr-domain attribute instead of the value
derived from the provider graph. The matching NodeFeatureGroup records
nvidia.com/gpu.clique as its source label key. The provider-supplied xclr-sub-domain is suppressed alongside xclr-domain
(matching the k8s engine behaviour); all fabric-tier attributes are still
published.
NodeFeatureGroup objects enumerate topology groups. A scheduler that wants to
place a workload within one leaf switch must still decide which leaf group to
use. This is different from native pod affinity, where the scheduler can compare
candidate nodes using a single topologyKey.
Large clusters may create many CRs and large status.nodes arrays. The design
notes in docs/design/nfd-engine-sdd.md include
the storage estimate and possible future NFD improvements such as group unions
and compressed node-name ranges.