Repository navigation
feat(inference): add dual DGX Spark express profile #8129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
bcac208
feat(inference): add dual DGX Spark express profile
ericksoa 7e33d7a
Merge remote-tracking branch 'origin/main' into feat/dual-dgx-spark-e…
ericksoa ba24aae
Merge remote-tracking branch 'origin/main' into feat/dual-dgx-spark-e…
ericksoa ad4daa5
refactor(inference): make serving profiles catalog-driven
ericksoa c56595f
Merge remote-tracking branch 'origin/main' into feat/dual-dgx-spark-e…
ericksoa 1365605
fix(inference): harden Spark binding claim
ericksoa 9437620
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 8c9a9ec
fix(inference): retire Spark discovery claims on uninstall
ericksoa 4321878
Merge origin/main into feat/dual-dgx-spark-express
ericksoa ff7c59b
docs(inference): clarify Spark claim cleanup
ericksoa 4af7988
refactor(inference): make serving profiles YAML-only
ericksoa b461955
fix(inference): bind Spark claim cleanup to receipt
ericksoa cbbac78
Merge origin/main into feat/dual-dgx-spark-express
ericksoa a263b93
fix(inference): generate catalog for semantic checks
ericksoa 296c549
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 00eb579
test(inference): keep receipt cleanup setup linear
ericksoa d900a9d
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 16afe65
test(vitest): stub catalog compiler in script harness
ericksoa f6674ae
fix(inference): package generated catalog as data
ericksoa 357526c
Merge remote-tracking branch 'origin/main' into feat/dual-dgx-spark-e…
ericksoa 6aa52ed
Merge remote-tracking branch 'origin/main' into feat/dual-dgx-spark-e…
ericksoa aec892a
fix(inference): address dual Spark review feedback
ericksoa 7013fc8
test(uninstall): keep unsafe-root cases linear
ericksoa 5c71614
fix(mcp): refresh reviewed runtime audit pins
ericksoa 475f5bd
refactor(inference): make managed clusters cardinality-driven
ericksoa 0e48fad
test(inference): keep topology coverage linear
ericksoa 02576b1
test(installer): align Spark profile wording
ericksoa 692731a
fix(inference): harden managed cluster contracts
ericksoa 975c688
chore(mcp): drop unrelated audit pin changes
ericksoa 08f838c
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 4e81e0c
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 604ce4c
Merge origin/main into feat/dual-dgx-spark-express
ericksoa 68c50fc
Merge origin/main into feat/dual-dgx-spark-express
ericksoa d54ae9a
merge: resolve conflicts with main
github-actions[bot] d051310
refactor(inference): use canonical serving catalog
ericksoa f397bed
merge: resolve conflicts with main
github-actions[bot] bfe1385
test(inference): reconcile Station receipt coverage
ericksoa fe2323b
merge: synchronize main
ericksoa 8fc4262
docs(inference): clarify managed runtime ownership
ericksoa a010d7d
test(inference): remove stale compiled preset
ericksoa 83b8b55
merge: resolve conflicts with main
github-actions[bot] e8506a1
fix(inference): reconcile managed catalog with main
ericksoa 30175c8
merge: synchronize main
ericksoa 78c9f53
merge: synchronize main
ericksoa e524c95
merge: synchronize main
ericksoa bcc28f8
fix(inference): pin managed model preparation code
ericksoa 8daa9b4
merge: synchronize main
ericksoa 9934865
test(inference): narrow managed recipe safety check
ericksoa ec4276e
Merge branch 'main' into feat/dual-dgx-spark-express
cv 1bc3c9f
merge: reconcile branch synchronization
ericksoa 3f7c4fe
merge: synchronize main
ericksoa 5cd60c0
fix(inference): validate managed catalog narrowing
ericksoa 318b5e5
merge: synchronize main
ericksoa 2ee7d11
merge: resolve conflicts with main
github-actions[bot] 655a464
merge: reconcile branch synchronization
ericksoa 3191c00
Merge branch 'main' into feat/dual-dgx-spark-express
cv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| --- | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| title: "Set Up vLLM on Two DGX Sparks" | ||
| sidebar-title: "Set Up vLLM on Two DGX Sparks" | ||
| description: "Qualify two trusted DGX Spark systems and start NemoClaw's Experimental distributed DeepSeek V4 Flash vLLM profile." | ||
| description-agent: "Sets up the Experimental managed vLLM profile for two DGX Spark systems, including selection, qualification, runtime ownership, and cleanup. Use when configuring NEMOCLAW_DGX_SPARK_PEER or NEMOCLAW_SERVING_PRESET." | ||
| keywords: ["nemoclaw dual dgx spark", "two dgx spark vllm", "deepseek v4 flash"] | ||
| content: | ||
| type: "how_to" | ||
| --- | ||
|
|
||
| Use this workflow to let DGX Spark Express qualify two trusted DGX Spark systems for distributed vLLM serving. | ||
| The profile serves DeepSeek V4 Flash 0731 through the managed `inference.local` route. | ||
|
|
||
| <Warning> | ||
| This profile is Experimental because physical two-node end-to-end (E2E) validation is pending. | ||
| Use it only for evaluation until the required physical validation is complete. | ||
| </Warning> | ||
|
|
||
| ## Understand Profile Selection | ||
|
|
||
| DGX Spark Express attempts automatic profile selection only after it selects the managed vLLM provider. | ||
| A provider other than `install-vllm`, an existing local inference route, `NEMOCLAW_VLLM_MODEL`, or `NEMOCLAW_VLLM_EXTRA_ARGS_JSON` remains authoritative. | ||
| Without explicit inference intent, the detector derives one exact counterpart from each qualified private `/30` rail. | ||
| It does not scan a subnet, add SSH host keys, add authorized keys, or change SSH configuration. | ||
|
|
||
| Both derived addresses must already have strict public-key SSH trust. | ||
| They must identify the same physical peer and the same SSH host key. | ||
| The detector performs read-only host probes only through that pinned identity. | ||
| After you confirm setup, NemoClaw repeats the read-only pair qualification and then writes an owner-only temporary SSH binding at `<selected-state-root>/dual-spark-managed-serving.json.ssh-binding/` for the install transaction. | ||
| The selected state root is `~/.nemoclaw/` for the default gateway or `~/.nemoclaw/gateways/<port>/` for a non-default gateway. | ||
| Declining setup creates no binding. After confirmation, NemoClaw attempts to remove the binding when setup fails or the durable runtime receipt is committed. | ||
| If cleanup cannot be confirmed and the claim remains without a durable runtime receipt, a new managed-vLLM install stops before mutation and preserves the claim for explicit recovery or removal. | ||
|
|
||
| When no pair qualifies during automatic selection, NemoClaw retains the existing single-DGX Spark managed vLLM path. | ||
| This ordinary no-match result occurs before the distributed image or model download starts. | ||
|
|
||
| Existing related runtime state is not an ordinary no-match result. | ||
| NemoClaw stops when either host has a related vLLM or DGX Station container, an ambiguous runtime inspection, or a listener on port `8000` or `25000`. | ||
| An existing durable dual-Spark or dual-Station runtime receipt, either receipt's copied SSH binding, an orphaned temporary dual-Spark discovery claim, or an SSH binding that conflicts with the new transaction also stops setup. | ||
| NemoClaw leaves the existing files, containers, and listeners untouched instead of replacing, repairing, adopting, or removing them. | ||
|
|
||
| Set `NEMOCLAW_DGX_SPARK_PEER` to request one exact pretrusted peer. | ||
| Set `NEMOCLAW_SERVING_PRESET=vllm.dgx-spark-gb10.dual.deepseek-v4-flash-0731` to request the exact serving profile. | ||
| Either setting makes qualification strict, so a missed requirement stops setup instead of selecting the single-DGX Spark profile. | ||
|
|
||
| ## Prepare Both Systems | ||
|
|
||
| Prepare both DGX Spark systems before you run the installer. | ||
| The automatic path requires all of these conditions on both systems: | ||
|
|
||
| - The host is an `arm64` DGX Spark with exactly one GB10 GPU. | ||
| - The current controller is a non-root user whose user ID (UID) matches the local host probe. | ||
| - Docker, NVIDIA Container Toolkit, Container Device Interface (CDI), and NVIDIA GPU readiness checks pass. | ||
| - One direct ConnectX-7 physical port exposes exactly two active `200,000 Mbps` Ethernet rails. | ||
| - Each rail has a maximum transmission unit (MTU) of at least `9,000` bytes and exactly one usable private IPv4 `/30` address. | ||
| - The two rails use distinct interfaces, MAC addresses, subnets, and reciprocal peer addresses. | ||
| - Each selected rail address has a dynamically resolved remote direct memory access over Converged Ethernet version 2 (RoCEv2) global identifier (GID). | ||
| - Both derived peer addresses have existing strict host-key and public-key SSH trust. | ||
| - `~/.cache/huggingface` already exists, belongs to the probed numeric Unix user ID and Unix group ID, and is writable by that user. | ||
| - Docker storage and the Hugging Face cache each report at least `1,024` available inodes. | ||
| - If `earlyoom` is installed, its active state is `inactive` on both systems. | ||
|
|
||
| NemoClaw treats an active or uninspectable `earlyoom` service as an unmet two-node requirement. | ||
| It does not stop, disable, or reconfigure that service. | ||
| An explicit pair or preset stops when this requirement is not met. | ||
|
|
||
| Refer to the [NVIDIA DGX Spark clustering guide](https://docs.nvidia.com/dgx/dgx-spark/spark-clustering.html) for the physical connection workflow. | ||
| The NemoClaw checks above remain the exact profile requirements. | ||
|
|
||
| ### Reserve Storage on Each System | ||
|
|
||
| The profile verifies storage before it pulls the image or downloads the model on either system. | ||
| For a cold cache, each system needs these approximate capacities: | ||
|
|
||
| | Filesystem | Required capacity | Included data | | ||
| |---|---:|---| | ||
| | Hugging Face cache | `170.936 GB` | `166.899 GB` model snapshot, `3.221 GB` staging reserve, and `0.816 GB` writable allowance. | | ||
| | Docker storage | `32.584 GB` | Three times the `9.788 GB` compressed image size plus a `3.221 GB` staging reserve. | | ||
| | Shared filesystem | `203.520 GB` | The combined cold-cache requirement when both paths share one filesystem. | | ||
|
|
||
| An exact cached image or exact pinned model snapshot removes its corresponding download requirement. | ||
| An unavailable capacity, ownership, directory, writability, or inode result leaves the two-node profile unqualified. | ||
|
|
||
| ## Restrict Network Access | ||
|
|
||
| Apply network controls before you start the distributed containers. | ||
|
|
||
| <Warning> | ||
| The pinned image runs as root in both containers. | ||
| Each container receives all host GPUs, `/dev/infiniband`, Docker host networking, host inter-process communication, `64 GB` of shared memory, and unlimited locked memory. | ||
| The launch does not use a read-only root filesystem, drop Linux capabilities, or set `no-new-privileges`. | ||
| The head binds HTTP port `8000` only to the qualified primary rail address. | ||
| vLLM applies bearer API key authentication to its authenticated API routes, including the inventory and chat routes that NemoClaw verifies. | ||
| The API key does not authenticate every endpoint on port `8000`. | ||
| vLLM exposes unauthenticated inference and operational endpoints on that port. | ||
| Trusted Docker administrators can inspect that API key in the head container environment. | ||
| The distributed rendezvous and RoCE traffic do not use that bearer credential. | ||
|
|
||
| Treat both DGX Spark systems and every host that can reach the direct rails as one trusted runtime boundary. | ||
| Allow port `8000` only from the OpenShell Docker subnet to the selected head rail address. | ||
| Deny port `8000` on management, LAN, and internet-facing interfaces. | ||
| Restrict port `25000`, NVIDIA Collective Communications Library (NCCL), and RoCE traffic to the exact reciprocal private rail addresses. | ||
| The address-specific bind reduces listener exposure but does not replace these firewall and trusted-boundary controls. | ||
| </Warning> | ||
|
|
||
| The detector qualifies both ConnectX-7 rails. | ||
| This profile revision binds vLLM, NCCL, Gloo, and tensor-parallel traffic to the first qualified rail in deterministic interface order. | ||
| Do not interpret two qualified `200,000 Mbps` rails as measured aggregate serving throughput. | ||
|
|
||
| ## Run Automatic Express Installation | ||
|
|
||
| Run the interactive installer on the system that should become the head. | ||
|
|
||
| ```bash | ||
| curl -fsSL https://www.nvidia.com/nemoclaw.sh | \ | ||
| <AgentOnly variant="openclaw"> | ||
| NEMOCLAW_AGENT=openclaw \ | ||
| </AgentOnly> | ||
| <AgentOnly variant="hermes"> | ||
| NEMOCLAW_AGENT=hermes \ | ||
| </AgentOnly> | ||
| <AgentOnly variant="deepagents"> | ||
| NEMOCLAW_AGENT=langchain-deepagents-code \ | ||
| </AgentOnly> | ||
| bash | ||
| ``` | ||
|
|
||
| Accept the usage notice and the **Run express install with these settings?** prompt. | ||
| DGX Spark Express prints the selected topology, immutable image, pinned model revision, cache paths, and worker-first launch order before image, model, or container mutation. | ||
|
|
||
| For optional authenticated model downloads, follow [Authenticate Hugging Face Downloads](set-up-vllm#authenticate-hugging-face-downloads) before you start the installer. | ||
| The public model can download anonymously, but Hugging Face can rate-limit anonymous transfers. | ||
|
|
||
| ## Select an Exact Pair | ||
|
|
||
| Use strict selection when you already know the pretrusted peer and want setup to stop on any missed requirement. | ||
| The following first-install example also selects the exact serving preset. | ||
|
|
||
| ```bash | ||
| curl -fsSL https://www.nvidia.com/nemoclaw.sh | \ | ||
| <AgentOnly variant="openclaw"> | ||
| NEMOCLAW_AGENT=openclaw \ | ||
| </AgentOnly> | ||
| <AgentOnly variant="hermes"> | ||
| NEMOCLAW_AGENT=hermes \ | ||
| </AgentOnly> | ||
| <AgentOnly variant="deepagents"> | ||
| NEMOCLAW_AGENT=langchain-deepagents-code \ | ||
| </AgentOnly> | ||
| NEMOCLAW_NON_INTERACTIVE=1 \ | ||
| NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 \ | ||
| NEMOCLAW_PROVIDER=install-vllm \ | ||
| NEMOCLAW_DGX_SPARK_PEER="<peer-host-or-address>" \ | ||
| NEMOCLAW_SERVING_PRESET=vllm.dgx-spark-gb10.dual.deepseek-v4-flash-0731 \ | ||
| NEMOCLAW_SANDBOX_NAME=my-assistant \ | ||
| bash | ||
| ``` | ||
|
|
||
| The peer must already pass strict public-key authentication and host-key checking without an interactive prompt. | ||
| The explicit target still must match the exact reciprocal rail topology. | ||
|
|
||
| ## Understand the Distributed Runtime | ||
|
|
||
| The compiled profile pins these artifacts: | ||
|
|
||
| - The image is `ghcr.io/anemll/dspark-vllm-gx10@sha256:a83948492cf13df455170fb42885f5ef4db54fefe0feff0f841ecbff464ac9d8`. | ||
| - The model is `deepseek-ai/DeepSeek-V4-Flash-0731` at revision `9e165c30e2704aec5d9d593cce3eebd58bbef1cb`. | ||
| - The served model ID is `deepseek-v4-flash-0731`. | ||
| - The context window is `1,048,576` tokens, with tensor parallelism `2` and pipeline parallelism `1`. | ||
|
|
||
| NemoClaw stages the exact image and model snapshot on both systems. | ||
| It mounts the pinned Hugging Face model data read-only into each long-running container. | ||
| It resolves the selected RoCEv2 GID during qualification instead of assuming a fixed GID index. | ||
|
|
||
| NemoClaw starts the headless rank-1 worker container before the rank-0 head container. | ||
| The worker must remain alive while waiting at the distributed rendezvous before the head starts. | ||
| NemoClaw passes the bearer API key only through the head container environment. | ||
| It does not add the credential or an environment-variable expansion to the vLLM process arguments. | ||
| The worker does not receive the API key. | ||
| Setup commits only after both container identities remain exact and authenticated model inventory and chat requests succeed. | ||
|
|
||
| ## Verify the Installed Route | ||
|
|
||
| After the installer completes, inspect the live route and sandbox inference health. | ||
|
|
||
| ```bash | ||
| $$nemoclaw my-assistant inference get | ||
| $$nemoclaw my-assistant status | ||
| ``` | ||
|
|
||
| Confirm that `inference get` reports the `vllm-local` provider and `deepseek-v4-flash-0731` model. | ||
| Continue only when the `Inference` row reports `reachable`. | ||
| This result confirms inference route reachability. | ||
| It does not establish physical two-node E2E validation or product support. | ||
|
|
||
| ## Preserve Ownership and Uninstall State | ||
|
|
||
| After runtime validation, NemoClaw writes the owner-only host-global receipt `~/.nemoclaw/dual-spark-vllm-runtime.json`. | ||
| It copies the pinned SSH binding to `~/.nemoclaw/dual-spark-vllm-runtime.json.ssh-binding/`. | ||
| The receipt contains the exact plan, container IDs, peer identity, and API key fingerprint, but not the API key. | ||
|
|
||
| NemoClaw stores the host-global bearer API key in the owner-only `~/.nemoclaw/dual-station-vllm-api-key` file. | ||
| The filename remains stable for managed vLLM compatibility across distributed profiles. | ||
| Users with Docker control can inspect the head container environment, so restrict Docker access to trusted administrators. | ||
|
|
||
| If receipt persistence fails, NemoClaw attempts to remove only the exact containers created by that attempt and reports any rollback removal it cannot confirm. | ||
| It does not remove an exact pair that existed before the attempt. | ||
|
|
||
| The containers have no Docker restart policy. | ||
| NemoClaw does not provide automatic runtime persistence across a Docker daemon restart or host reboot. | ||
| A stopped, partial, mismatched, or unhealthy pair remains a conflict and is not repaired automatically. | ||
|
|
||
| Run a full uninstall to remove the exact receipt-owned pair. | ||
|
|
||
| ```bash | ||
| $$nemoclaw uninstall | ||
| ``` | ||
|
|
||
| Full uninstall revalidates both exact container IDs before it removes them and retires the receipt and copied SSH binding. | ||
| If revalidation or removal fails, uninstall stops before other cleanup and preserves the receipt for a retry. | ||
| A gateway-scoped uninstall preserves the host-global pair, receipt, SSH binding, and API key while another gateway remains. | ||
| Pair cleanup does not delete the Hugging Face model cache. | ||
|
|
||
| ## Related Topics | ||
|
|
||
| - [Set Up vLLM](set-up-vllm) for existing servers, single-host managed setup, model selection, and download authentication. | ||
| - [Set Up vLLM on Two DGX Stations](set-up-vllm-on-two-dgx-stations) for the separate DGX Station distributed profile. | ||
| - [Uninstall NemoClaw](../../manage-sandboxes/operate-sandboxes/uninstall-nemoclaw) for full and gateway-scoped uninstall behavior. | ||
| - [Host Files and State](../../reference/host-files-and-state) for managed inference receipt and API key locations. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.