Skip to content

Commit f74b1af

Browse files
feat(slinky-topograph): topograph component with slinky engine (NVIDIA#1737)
Signed-off-by: Ravi Shankar <ravish@nvidia.com> Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com> Co-authored-by: Ravi Shankar <ravish@nvidia.com>
1 parent ffe1d9c commit f74b1af

12 files changed

Lines changed: 646 additions & 5 deletions

File tree

demos/cuj1-slinky-slurm.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Slurm leaves are built from criteria flags (`--service`, `--platform slurm`, …
2626

2727
## Generate Recipe (Query Mode)
2828

29-
Pick the row that matches your cluster. Each resolves to a slurm leaf with three inline Slinky components: `slinky-slurm-operator-crds`, `slinky-slurm-operator`, and `slinky-slurm`.
29+
Pick the row that matches your cluster. Each resolves to a slurm leaf with at least three inline Slinky components: `slinky-slurm-operator-crds`, `slinky-slurm-operator`, and `slinky-slurm`. The GKE and Kind leaves also include `slinky-topograph` (topology-aware scheduling) — GKE with the `gcp` provider, Kind with the `test` provider and a fixed topology fixture. The EKS leaf does not include it today; see [Slinky Slurm Inline Components](../docs/integrator/recipe-development.md#slinky-slurm-inline-components) to add it to another leaf.
3030

3131

3232
| Cloud | Command | Leaf overlay |
@@ -135,7 +135,7 @@ Set `--storage-class` to a StorageClass that exists (`kubectl get storageclass`)
135135
cd ./bundle && chmod +x deploy.sh && ./deploy.sh
136136
```
137137

138-
Deploy order: `cert-manager``slinky-slurm-operator-crds``slinky-slurm-operator``slinky-slurm`.
138+
Deploy order: `cert-manager``slinky-slurm-operator-crds``slinky-slurm-operator``slinky-slurm` (→ `slinky-topograph` on the GKE and Kind leaves, after `slinky-slurm` so the slurm chart owns the ConfigMap Topograph patches).
139139

140140
```shell
141141
kubectl rollout status -n slinky deploy/slurm-operator
@@ -257,7 +257,7 @@ Cluster instance only (keep operator + CRDs):
257257
helm uninstall slinky-slurm -n slurm
258258
```
259259

260-
Full Slurm stack:
260+
Full Slurm stack (without topograph):
261261

262262
```shell
263263
helm uninstall slinky-slurm -n slurm
@@ -266,6 +266,16 @@ helm uninstall slinky-slurm-operator-crds -n slinky
266266
kubectl delete ns slurm slinky --ignore-not-found
267267
```
268268

269+
Full Slurm stack with topograph:
270+
271+
```shell
272+
helm uninstall slinky-topograph -n topograph
273+
helm uninstall slinky-slurm -n slurm
274+
helm uninstall slinky-slurm-operator -n slinky
275+
helm uninstall slinky-slurm-operator-crds -n slinky
276+
kubectl delete ns slurm topograph slinky --ignore-not-found
277+
```
278+
269279
Helm does not remove CRDs or PVCs by default; delete manually when you need a clean re-install.
270280

271281
## Success

docs/integrator/recipe-development.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,71 @@ Only use this pattern when the content is truly uniform across the wildcard dime
159159
- Criteria: not inherited (each recipe defines its own)
160160
- Mixin constraints/components must not conflict with the inheritance chain or other mixins
161161

162+
### Slinky Slurm Inline Components
163+
164+
Leaves that need topology-aware scheduling can optionally add `slinky-topograph` as a fourth `componentRef`. Its `dependencyRefs` include `slinky-slurm`, so it deploys **after** the Slurm cluster chart: `slinky-slurm` renders and owns the `slinky-slurm-config-extra` ConfigMap (from its `configFiles`, mounted into slurmctld via the Controller CR's `configFileRefs`), and Topograph patches only that ConfigMap's `topology.conf` key on each sync, preserving the chart-owned `cgroup.conf`/`gres.conf` keys — Helm has to own the ConfigMap first, or a later `helm upgrade` on `slinky-slurm` would fight Topograph for ownership. The `overrides` block supplies the provider and engine that are specific to each leaf:
165+
166+
```yaml
167+
- name: slinky-topograph
168+
type: Helm
169+
valuesFile: components/slinky-topograph/values.yaml
170+
dependencyRefs:
171+
- slinky-slurm-operator
172+
- slinky-slurm-operator-crds
173+
- slinky-slurm # deploy after Slurm so Helm already owns config-extra
174+
overrides:
175+
global:
176+
provider:
177+
name: gcp # cloud provider: gcp | aws | oci | nebius | …
178+
engine:
179+
name: slinky # scheduler consumer: slinky | slurm | k8s | graph
180+
181+
- name: slinky-slurm
182+
type: Helm
183+
valuesFile: components/slinky-slurm/values.yaml
184+
dependencyRefs:
185+
- slinky-slurm-operator
186+
- slinky-slurm-operator-crds
187+
overrides:
188+
configFiles:
189+
# Seed so topology.conf exists in slinky-slurm-config-extra from first
190+
# boot; Topograph overwrites this key after each successful sync.
191+
# NOTE: helm upgrade resets the key to this seed until the next
192+
# Topograph sync.
193+
topology.conf: |
194+
# Managed by NVIDIA Topograph (engine: slinky). Pre-sync placeholder.
195+
SwitchName=aicr-preseed Nodes=aicr-preseed-node
196+
controller:
197+
extraConfMap:
198+
TopologyPlugin: "topology/tree"
199+
# Reload path: the reconfigure sidecar loads Topograph's topology.conf
200+
# updates into the running slurmctld (rollout hash excludes configFileRefs).
201+
inplaceReconfigure: true
202+
# ... GPU GRES and other leaf-specific tuning ...
203+
```
204+
205+
For cloud providers (gcp, aws, oci, nebius, …), `slinky-topograph` requires IAM access to call the cloud's topology API. For GKE, bind a GCP service account that has `roles/compute.viewer` on the project via Workload Identity:
206+
207+
```yaml
208+
overrides:
209+
global:
210+
provider:
211+
name: gcp
212+
serviceAccount:
213+
annotations:
214+
iam.gke.io/gcp-service-account: <sa-name>@<project-id>.iam.gserviceaccount.com
215+
```
216+
217+
If you prefer not to bake the GCP service account into the recipe, supply it at bundle time instead:
218+
219+
```bash
220+
aicr bundle --recipe recipe.yaml \
221+
--set-json 'slinkytopograph:serviceAccount.annotations={"iam.gke.io/gcp-service-account":"<sa-name>@<project-id>.iam.gserviceaccount.com"}' \
222+
-o ./bundle
223+
```
224+
225+
For `provider.name: dra` (Kubernetes Dynamic Resource Allocation, GA in K8s 1.34), topology is sourced from the DRA API — no cloud provider IAM or ServiceAccount annotations are needed. Use `dra` for clusters actually running DRA drivers with GPU resource claims. Kind-based CI clusters should use the `test` provider with a model fixture instead (as this repo's `h100-kind-training-slurm` overlay does) — a CPU-only Kind cluster has no DRA resources for the `dra` provider to read.
226+
162227
### Inference performance constraints
163228

164229
The `inference-perf` performance check reads named entries from

docs/user/component-catalog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ The source of truth is [`recipes/registry.yaml`](https://github.com/NVIDIA/aicr/
3939
| **slinky-slurm-operator-crds** | Custom Resource Definitions for the SchedMD Slinky Slurm operator. Installs the `slinky.slurm.net` CRDs (Controller, NodeSet, LoginSet, Accounting, RestApi, Token). Installed separately to support CRD lifecycle management. | [Slinky Slurm Operator](https://github.com/SlinkyProject/slurm-operator) |
4040
| **slinky-slurm-operator** | SchedMD Slinky Slurm operator and admission webhook. Manages the lifecycle of Slurm clusters declared via Slinky CRs (Controller, NodeSet, LoginSet, Accounting, RestApi, Token). AICR's system node-selector and toleration bundle flags apply to both deployments; affinity remains available through component values or typed overrides. | [Slinky Slurm Operator](https://github.com/SlinkyProject/slurm-operator) |
4141
| **slinky-slurm** | Slinky-managed Slurm cluster instance: Controller (slurmctld) + LoginSet (sackd/sshd) + NodeSet (slurmd) + RestApi (slurmrestd). Reconciled by `slinky-slurm-operator`. Declared inline per slurm leaf overlay alongside `slinky-slurm-operator-crds` and `slinky-slurm-operator` (matching the dynamo-platform pattern) so each leaf can carry its own GPU/GRES tuning. IMEX-capable leaves attach a fixed NVIDIA DRA `ComputeDomain` as a pre-manifest before the Slurm chart; the DRA driver reconciles it asynchronously into the `ResourceClaimTemplate` consumed by the NodeSet. Accounting (slurmdbd) requires an external MariaDB and is disabled in defaults — see `recipes/components/slinky-slurm/values.yaml`. | [Slinky Slurm Cluster Chart](https://github.com/SlinkyProject/slurm-operator/tree/main/helm/slurm) |
42+
| **slinky-topograph** | Slinky/Slurm-scoped instance of Topograph — queries cloud provider topology APIs (GCP, AWS, OCI …) to generate Slurm `topology.conf`, enabling topology-aware placement decisions in the Slinky-managed scheduler. **Not installed by default**; leaf overlays opt in by adding an explicit `componentRef` entry for `slinky-topograph` — the `componentRef` is what schedules the release; `dependencyRefs` alone does not install anything. That `componentRef` declares `slinky-slurm` as a `dependencyRef` to deploy **after** it: `slinky-slurm` renders and owns the `slinky-slurm-config-extra` ConfigMap (from its `configFiles`, mounted into slurmctld via the Controller CR's `configFileRefs`), and Topograph patches only that ConfigMap's `topology.conf` key on each sync, preserving the chart-owned `cgroup.conf`/`gres.conf` keys — Helm has to own the ConfigMap first. `TopologyPlugin: topology/tree` is set per-leaf via `slinky-slurm`'s `controller.extraConfMap`. Includes the `node-observer` sub-chart, which watches the topograph API pod and regenerates topology on restarts or selected node/pod changes. Requires cloud provider IAM access (e.g. GCP `roles/compute.viewer` for Workload Identity). | [Topograph](https://github.com/NVIDIA/topograph) |
4243
| **nfd-ocp-olm** | OLM installer for Node Feature Discovery on OpenShift. Creates the OperatorGroup and Subscription resources that install NFD via the Operator Lifecycle Manager. Paired with `nfd-ocp`. OCP-specific. | [Node Feature Discovery (Certified)](https://catalog.redhat.com/software/container-stacks/detail/5ec53e8c110f56bd24f5f8db) |
4344
| **nfd-ocp** | Node Feature Discovery CR for OpenShift. Configures NFD's operand (worker, topology updater) via a NodeFeatureDiscovery custom resource. Deployed after `nfd-ocp-olm`. OCP-specific. | [Node Feature Discovery](https://github.com/kubernetes-sigs/node-feature-discovery) |
4445
| **gpu-operator-ocp-olm** | OLM installer for the GPU Operator on OpenShift. Creates the OperatorGroup and Subscription resources that install the certified GPU Operator via the Operator Lifecycle Manager. Paired with `gpu-operator-ocp`. OCP-specific. | [NVIDIA GPU Operator (Certified)](https://catalog.redhat.com/software/container-stacks/detail/5e7b210b8a3c1e00013d636d) |
@@ -54,6 +55,7 @@ Not every component appears in every recipe. The recipe engine selects component
5455
- **Cloud-specific components** (aws-efa, aws-ebs-csi-driver) are added when the service matches. OCP recipes replace base components (gpu-operator, nfd, network-operator) with OLM+CR pairs (e.g., `gpu-operator-ocp-olm` + `gpu-operator-ocp`).
5556
- **Intent-specific components** (agentgateway, agentgateway-crds) are added based on workload intent (e.g., inference recipes include the inference gateway).
5657
- **Platform-specific components** (slinky-slurm-operator, slinky-slurm, kubeflow-trainer, dynamo-platform) are added when the recipe selects a matching `--platform`. For `--platform slurm`, all three core Slinky pieces (`slinky-slurm-operator-crds`, `slinky-slurm-operator`, `slinky-slurm`) are declared inline per slurm leaf overlay — the same shape `dynamo-platform` uses across `*-inference-dynamo` leaves. IMEX-capable Slurm leaves attach a fixed ComputeDomain through `slinky-slurm.preManifestFiles` so slurmd pods can consume DRA-provisioned IMEX channels. Leaves that want the operator only inline the CRDs + operator and omit the `slinky-slurm` componentRef. For an end-to-end walkthrough (recipe → bundle → install → validate → `srun` smoke job on EKS, GKE, or Kind), see [`demos/cuj1-slinky-slurm.md`](https://github.com/NVIDIA/aicr/blob/main/demos/cuj1-slinky-slurm.md).
58+
- **Topology-aware optional components** (`slinky-topograph`) are not installed by default. Opting in requires an explicit `componentRef` entry for `slinky-topograph` in the leaf overlay — the `componentRef` is what installs it; `dependencyRefs` alone does not. That `componentRef` declares `slinky-slurm` as a `dependencyRef`, so Topograph deploys after the Slurm cluster chart, which owns the ConfigMap Topograph patches. See the wiring example in the [Recipe Development Guide](../integrator/recipe-development.md#slinky-slurm-inline-components).
5759
- **Accelerator/OS-specific tuning** (nodewright-customizations, nvidia-dra-driver-gpu) varies by hardware and OS combination.
5860

5961
### NFD Topology Updater

docs/user/container-images.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ A machine-readable **CycloneDX 1.6 JSON** companion to this page is produced by
1919
<!-- BEGIN AICR-BOM -->
2020
## Summary
2121

22-
- Components: **33**
23-
- Unique images: **85**
22+
- Components: **34**
23+
- Unique images: **86**
2424
- Distinct registries: **11**
2525

2626
Registries: `602401143452.dkr.ecr.us-west-2.amazonaws.com`, `cr.agentgateway.dev`, `docker.io`, `gcr.io`, `ghcr.io`, `gke.gcr.io`, `nvcr.io`, `public.ecr.aws`, `quay.io`, `registry.k8s.io`, `us-docker.pkg.dev`
@@ -64,6 +64,7 @@ _Rendering fidelity:_ `catalog-parity: charts are rendered with the shared recip
6464
| slinky-slurm | helm | slurm | 1.2.0 | 5 |
6565
| slinky-slurm-operator | helm | slurm-operator | 1.2.0 | 2 |
6666
| slinky-slurm-operator-crds | helm | slurm-operator-crds | 1.2.0 | 0 |
67+
| slinky-topograph | helm | topograph/topograph | 0.5.0 | 1 |
6768

6869
## Version variants
6970

@@ -265,6 +266,10 @@ _No images extracted._
265266

266267
_No images extracted._
267268

269+
### slinky-topograph
270+
271+
- `ghcr.io/nvidia/topograph:v0.5.0`
272+
268273
### kube-prometheus-stack@83.7.0 (variant)
269274

270275
- `docker.io/grafana/grafana:12.4.3`

pkg/recipe/deployment_order_guard_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,20 @@ func TestDeploymentOrderGuards(t *testing.T) {
236236
requiredDeps: map[string][]string{
237237
"slinky-slurm-operator": {"cert-manager", "slinky-slurm-operator-crds"},
238238
"slinky-slurm": {"slinky-slurm-operator", "slinky-slurm-operator-crds"},
239+
"slinky-topograph": {"slinky-slurm-operator", "slinky-slurm-operator-crds", "slinky-slurm"},
239240
},
240241
requiredOrdering: [][2]string{
241242
{"cert-manager", "slinky-slurm-operator"},
242243
{"slinky-slurm-operator-crds", "slinky-slurm-operator"},
243244
{"slinky-slurm-operator", "slinky-slurm"},
244245
{"slinky-slurm-operator-crds", "slinky-slurm"},
246+
// slinky-topograph deploys AFTER slinky-slurm: topograph's slinky
247+
// engine create-or-updates the ConfigMap named by
248+
// topologyConfigmapName (slinky-slurm-config-extra). The slurm
249+
// chart must create that CM first or Helm install fails on
250+
// ownership metadata. Topograph then patches only the
251+
// topology.conf key (maps.Copy), preserving chart-owned keys.
252+
{"slinky-slurm", "slinky-topograph"},
245253
{"gpu-operator", "nvsentinel"},
246254
},
247255
},
@@ -258,12 +266,20 @@ func TestDeploymentOrderGuards(t *testing.T) {
258266
requiredDeps: map[string][]string{
259267
"slinky-slurm-operator": {"cert-manager", "slinky-slurm-operator-crds"},
260268
"slinky-slurm": {"slinky-slurm-operator", "slinky-slurm-operator-crds"},
269+
"slinky-topograph": {"slinky-slurm-operator", "slinky-slurm-operator-crds", "slinky-slurm"},
261270
},
262271
requiredOrdering: [][2]string{
263272
{"cert-manager", "slinky-slurm-operator"},
264273
{"slinky-slurm-operator-crds", "slinky-slurm-operator"},
265274
{"slinky-slurm-operator", "slinky-slurm"},
266275
{"slinky-slurm-operator-crds", "slinky-slurm"},
276+
// slinky-topograph deploys AFTER slinky-slurm: topograph's slinky
277+
// engine create-or-updates the ConfigMap named by
278+
// topologyConfigmapName (slinky-slurm-config-extra). The slurm
279+
// chart must create that CM first or Helm install fails on
280+
// ownership metadata. Topograph then patches only the
281+
// topology.conf key (maps.Copy), preserving chart-owned keys.
282+
{"slinky-slurm", "slinky-topograph"},
267283
},
268284
},
269285
}

0 commit comments

Comments
 (0)