NVKE GB200 Setup
The gb200-nvke-ubuntu-training recipe targets NVKE (NVIDIA Kubernetes Engine,
formerly NKE): bare-metal GB200 NVL trays provisioned by Forge/NICo, running
Ubuntu 24.04 with NVIDIA’s -nvidia-64k kernel. It is a Preview coordinate.
gb200-nvke-ubuntu-training-kubeflow (--platform kubeflow) is the same leaf
plus Kubeflow Trainer through the platform-kubeflow mixin.
Cluster prerequisites
- Kubernetes 1.34 or newer (DRA
resource.k8s.io/v1for ComputeDomains). - Nodes carry
providerID: nico://<uuid>.aicr snapshotmaps that scheme toservice: nvke, soaicr recipe --snapshotselects this recipe without--service. - GPU nodes are untainted by the provisioner and run nothing GPU- or fabric-related: GPU Operator installs the driver, toolkit and GDRCopy.
- Control-plane nodes carry GPU-node labels they do not earn
(
nvidia.com/gpu.present=true,nvidia.com/gpu.deploy.driver=true,feature.node.kubernetes.io/pci-15b3.present=truefrom the BlueField-3) while having no GPU. Anything that selects GPU nodes by those labels alone also selects the control plane; the recipe excludes control-plane nodes explicitly where that matters (rdma-modules), anddeploy.sh’s DRA driver-migration gate waits its full timeout on them before continuing. - The primary CNI is OVN-Kubernetes on the BlueField-3, bound to the host’s
inbox
mlx5_core. It is the only CNI on the image: no multus, no reference plugins beyond what OVN-Kubernetes needs. - Some NVKE builds hand every pod on the pod network one BlueField-3 VF: an
sdn-mutatorwebhook adds anvidia.com/asap2_vf: 1request and a node advertises 28, which caps non-hostNetwork pods at 28 per node, platform pods included (the recipe’s own DaemonSets take eight slots per GPU node for GPU Operator plus nvsentinel, NFD, DRA and monitoring). The reference tenant has neither the webhook nor the resource. Where it does, keep a system node pool for the cluster-scoped charts or expect pods to stay Pending onInsufficient nvidia.com/asap2_vf. - East-west fabric: four ConnectX-7 InfiniBand rails per tray (
mlx5_0,mlx5_1,mlx5_3,mlx5_4), active NDR, no IPoIB netdevs until the recipe loadsib_ipoib.mlx5_2is the BlueField-3 host representor. Firmware enables SR-IOV withNUM_OF_VFS16 per PF (sriov_totalvfs), which is the count the recipe requests (see below). - InfiniBand traffic between hosts needs every tenant port, PF and VF, to be a
full member of a common partition: a P_Key with the
0x8000bit set, either0xffff(default partition) or a tenant P_Key assigned by the fabric (UFM). On the reference cluster every port, including allocated VFs, held only0x7fff(limited membership): links are up and LIDs assigned, but every RDMA connection between hosts fails with retry-exceeded, even same-tray loopback through the switch. Check the non-zero entries under/sys/class/infiniband/mlx5_*/ports/1/pkeys/. VFs are separate virtual ports with their own GUIDs, so the fabric must add the VF GUIDs to the partition too (UFM GUID mapping or ib-kubernetes); fixing the PFs alone is not enough. The fabric must provision partition membership for each VF GUID. This recipe does not select a non-default P_Key for IPoIB interfaces (the pinnedSriovIBNetworkhas no such field, and the ib-sriov CNIpkeyonly informs ib-kubernetes, which this recipe does not install); native RDMA applications can select their own P_Key index. Traffic between trays in the same NVLink domain uses multi-node NVLink and does not need this; it matters for jobs spanning NVLink domains and for IPoIB or RDMA storage. rdma_ucm,ib_umadandib_ipoibare not loaded by the NVKE image andrdma-coreis not installed (the modules ship inlinux-modules-<kernel>); the recipe’srdma-modulescomponent loads them (see below). A modules-load.d entry for all three in the image makes that component a no-op. Installingrdma-coreinstead also works: its udev rules load/etc/rdma/modules/infiniband.conf(ib_ipoib,ib_umad) andrdma.conf(ib_iser,ib_uverbs,rdma_ucm,xprtrdma,svcrdma), a superset of what the recipe loads.- The tenant image ships no multus:
/etc/cni/net.dholds only10-ovn-kubernetes.conf,/opt/cni/binhas nomultus, and no DaemonSet or package provides one (measured 2026-10-28). OVN-Kubernetes runs with--enable-multi-network, but that serves only its own NetworkAttachmentDefinitions; a pod that requestssriov-network-rail-<n>on such a node gets the VF allocated and no IB interface, silently. The NicClusterPolicy therefore carriessecondaryNetwork.multusandcniPlugins; the NVKE image contract is OVN-Kubernetes only, and multus is the recipe’s to install. The operator renders the multus DaemonSet with--skip-config-watch, so the service-account token multus copies intomultus.kubeconfigis not refreshed on rotation. Under default API-server settings the legacy-token extension keeps that copy valid for one year from issuance (serviceaccount.ExpirationExtensionSeconds); other settings may shorten it. Restart the multus pods before it expires to rewrite the file. The SR-IOV policies select only the ConnectX-7 root devices.
Never install DOCA-OFED on these nodes
The Network Operator in this recipe ships no ofedDriver. The host runs
the inbox mlx5_core and OVN-Kubernetes rides on it. A DOCA driver container
unloads mlx5_core to replace it, and the node’s primary address disappears
with it; a reboot restores the inbox driver and the operator applies the
DOCA driver again. This was observed on NVKE GB200 and bare-metal GB300 clusters
with recipes that carried an ofedDriver block. Do not add one back for NVKE,
and do not combine this recipe with another Network Operator installation.
The same posture applies to GPUDirect RDMA: it runs over DMA-BUF. The recipe
sets no driver.rdma value (no nvidia-peermem, which has no build for the
64k-page Grace kernel and needs OFED symbols) and installs the
NVreg_GrdmaPciTopoCheckOverride=1 module parameter through the
kernel-module-params ConfigMap, which the nccl-all-reduce-bw-net preflight
requires.
Containerd configuration
The recipe sets gpu-operator.toolkit.env.RUNTIME_CONFIG_SOURCE=file so the
NVIDIA toolkit reads /etc/containerd/config.toml directly. NVKE v0.22.0’s
qualified Ubuntu image ships containerd 2.3.0 with a version 3 configuration.
The default command source reads containerd config dump, which migrates the
effective configuration to version 4. A version 4 NVIDIA drop-in imported by
the version 3 root prevents containerd from starting. Reading the file keeps
the NVIDIA drop-in at the host’s configuration version without changing the
node image or migrating its root configuration. The same toolkit defect took
down AKS nodes with a version 2 root (NVIDIA/aicr#1688).
The toolkit also refuses NVIDIA_VISIBLE_DEVICES from unprivileged containers
(ACCEPT_NVIDIA_VISIBLE_DEVICES_ENVVAR_WHEN_UNPRIVILEGED=false). GPUs reach a
workload only through a nvidia.com/gpu request or a DRA claim; an unprivileged
pod that selects the nvidia RuntimeClass and sets NVIDIA_VISIBLE_DEVICES=all
sees none. Privileged management pods (the GPU Operator operands, NVSentinel’s
metadata-collector) keep the env-var path, because the toolkit always honors it for
privileged containers. Unlike the AKS and OpenShift recipes, this one leaves
ACCEPT_NVIDIA_VISIBLE_DEVICES_AS_VOLUME_MOUNTS at its default of false:
DEVICE_LIST_STRATEGY still emits the volume-mount device list beside CDI, but
the toolkit ignores it while the flag is false, and CDI is what injects
devices here.
SR-IOV InfiniBand
The Network Operator chart enables the SR-IOV Network Operator and the
Maintenance Operator (external drainer, one node at a time). The
NicClusterPolicy carries nvIpam, multus and the reference CNI plugins. Per
rail, the sriov-ib-networks component (manifest-only, ordered after
network-operator) supplies one nv-ipam IPPool (10.255.<4n>.0/22,
outside the 192.168.0.0/16 pod network), one SriovNetworkNodePolicy
(linkType: IB, isRdma: true, deviceType: netdevice, numVfs: 16,
selected by the rail’s
PCI root device) and one SriovIBNetwork whose NetworkAttachmentDefinition
lands in default. Nodes advertise nvidia.com/sriov_resource_rail_0 to
_3, 16 each. A pod takes one VF per rail and the matching attachments:
This is the shape k8s-launch-kit generates for
--deployment-type sriov --fabric infiniband on this topology, with the
Maintenance Operator budget set to one node, with numVfs raised
from l8k’s 8 to the firmware’s 16, with the IPPool subnets moved from l8k’s
192.168.<4n>.0/22 to 10.255.<4n>.0/22 (outside the OVN-Kubernetes pod
network), and with the SR-IOV config daemon’s
mellanox plugin disabled (sriovOperatorConfig.disablePlugins). That
plugin rewrites firmware NUM_OF_VFS to exactly numVfs and then runs
mstfwreset -l 3, which this tray’s firmware rejects (“not supported in the
current state of this device”); with it enabled, a policy that differed from
the firmware count drained the node and then looped on the reset with the
node cordoned. With the plugin off, firmware is a host prerequisite (SR-IOV
enabled, NUM_OF_VFS, IB link type) and VF creation is a sysfs write with no
drain or reboot, so numVfs must not exceed the firmware count. Check
mstconfig -d <pf> q NUM_OF_VFS before changing numVfs. The policies and pools select nodes by
feature.node.kubernetes.io/rdma.available=true rather than
pci-15b3.present: the control plane carries that label (and
pci-0302_10de.present) without any ConnectX-7, and when it was selected
the operator placed a device-plugin pod there whose init container waited
forever, which the expected-resources check flags. Enabling the
SR-IOV subchart on a Network Operator release that was installed without it
needs charts/sriov-network-operator/crds applied first: Helm installs a
subchart’s CRDs only on a fresh install, and validates the rendered
SriovOperatorConfig before the chart’s own CRD-upgrade hook runs.
The IPPool CRD is created by the operator while it reconciles the
NicClusterPolicy, not by the chart, so sriov-ib-networks can be applied
before the CRD exists. deploy.sh retries the release until it does. With
Argo CD or Terraform, build with --readiness-hooks: the network-operator
readiness gate waits for the NicClusterPolicy to reach ready, which the
operator reports only after its nv-ipam state, CRDs included, is applied, so
the pools follow it. Helmfile cannot take --readiness-hooks and its bundle
has no CRD wait, so install it in two stages. kubectl wait fails at once on
an object that does not exist yet, so wait for the CRD to be created before
waiting for it to be Established (--for=create needs kubectl 1.31 or later):
Flux does not support readiness hooks either. If sriov-ib-networks
exhausts its install retries on the missing CRD, wait for the CRD to be
created and Established, then reset the release:
The sriov-ib-networks health check asserts the CRD is Established, so
aicr validate records that it landed. Measured on a reference tenant after
a full teardown: the CRD appeared five seconds after the NicClusterPolicy
and the policy was ready four seconds later; the gate held
sriov-ib-networks until then.
When tearing the fabric down, uninstall sriov-ib-networks and wait for
every SriovNetworkNodeState to return to Succeeded before uninstalling
network-operator: removing the policies makes the config daemon request a
drain through the Maintenance Operator, and uninstalling the operators while
that drain is in flight orphans the NodeMaintenance, which leaves the node
cordoned with nothing left to release it. The Maintenance Operator’s
controller is what removes the maintenance.nvidia.com/finalizer from a
NodeMaintenance and uncordons its node, so with the operator gone either
reinstall network-operator and let it finish the cleanup, or recover by hand:
A shared-HCA variant (rdmaSharedDevicePlugin, one pooled nvidia.com/mlnxnics
resource over the PFs, no IPoIB) was qualified first on the same cluster and
passed the deployment and conformance phases. It is not selectable from this
recipe; it survives only in the history of
NVIDIA/aicr#3295 before the SR-IOV
switch.
rdma-modules and node tainting
rdma-modules is a manifest-only component carrying one NodeWright CR that
loads rdma_ucm, ib_umad and ib_ipoib and writes
/etc/modules-load.d/aicr-rdma-ulp.conf on every pci-15b3.present node that
is not a control-plane node (the control plane also carries a BlueField-3; an
auto-tainted node whose taints the package cannot tolerate would otherwise
stay tainted). The package has no interrupt (no cordon, drain or reboot).
runtimeRequired: true with autoTaintNewNodes lets nodewright taint GPU
nodes until the modules are loaded, so the SR-IOV config daemon and GPU
workloads never start against an empty /dev/infiniband or VFs without
IPoIB netdevs. The CR selects feature.node.kubernetes.io/pci-15b3.present=true
by default, the cohort the NicClusterPolicy pins its DaemonSets to.
--accelerated-node-selector and --accelerated-node-toleration reach only
this component: the NicClusterPolicy keeps its fixed affinity and GPU Operator
selects nodes by its own labels, so a different selector must still cover every
node the fabric DaemonSets land on, or those nodes never get the modules and are
never gated.
Disable the taint with --set rdmamodules:autoTaintNewNodes=false. On images
that already load all three modules, disable the component in the recipe rather
than at bundle time: set overrides.enabled: false on the rdma-modules
componentRef in recipe.yaml (or in a --data overlay), which drops it from
the bundle and from the deployment phase’s expected resources alike. A
bundle-time --set rdmamodules:enabled=false is not persisted, so
aicr validate would still assert the CR.
Generate and validate
aicr validate runs the deployment and conformance phases against the live
cluster, so the bundle must be deployed before it.
Performance thresholds are copied from the GB200 OKE recipe. The
nccl-benchmark-profile constraint names the gb200/oke runtime.
nccl-all-reduce-bw-nvls runs with it and measured 839.5 GB/s on the
reference tenant (2026-10-29), the NVKE NVLS baseline; the >= 500 floor is
kept until the result is recorded in qualification evidence.
nccl-all-reduce-bw-net cannot schedule: that runtime’s workers request
nvidia.com/mlnxnics, which this leaf does not expose, so it waits for a
gb200/nvke runtime requesting the per-rail VFs and attachments.
Known gaps
- No
gb200/nvkeNCCL runtime yet:nccl-all-reduce-bw-netborrows thegb200/okeruntime, whose workers requestnvidia.com/mlnxnics, which this leaf does not expose, so that check cannot schedule. - The reference fabric has not passed RDMA traffic (limited P_Key membership, see prerequisites), so neither the SR-IOV nor the earlier shared-HCA shape has NCCL evidence.
nccl-all-reduce-bw-nvlspasses on the reference tenant: 839.5 GB/s across both trays (8 GPUs, one multi-node NVLink domain), measured 2026-10-29. It needs DRA driver 0.5.1: the NVKE API server enablesOwnerReferencesPermissionEnforcement, under which 0.5.0’s daemon on the second tray cannot join the trays’ shared NVLink clique (see Upgrade Notes:nvidia-dra-driver-gpu0.5.0 to 0.5.1).- No published evidence yet.
- KWOK profiles model scheduling only; they cannot validate RDMA traffic.