Repository navigation
Release v0.6.0
NVCRE v0.6.0
The NVIDIA Cluster Readiness Engine (NVCRE) is a Kubernetes controller that certifies GPU clusters before production use. It runs real training and communication workloads across topology-aware node groups, measures goodput and bandwidth, detects hardware failures, and reports every failed node with a reason. See the README for the full feature list.
Highlights
This release focuses on certifying clusters that carry no GPU product label, a read-only MCP server for certification state, and keeping the EFA fabric on AWS H100 and GB200.
GPU architecture no longer depends on a node label (#379). Every architecture decision NVCRE makes used to read nvidia.com/gpu.product, which GPU Feature Discovery writes. A cluster that claims GPUs through Dynamic Resource Allocation runs no GFD, so no node carried the label and every certification failed with cannot determine GPU architecture. NVCRE now reads the architecture from the gpu.nvidia.com ResourceSlices the DRA driver publishes, normalized to the exact string GFD would have written, so a mixed GFD and DRA fleet still passes the homogeneity check. The manager role gains get/list/watch on resource.k8s.io resourceslices; a missing grant leaves those nodes unlabeled rather than failing the reconcile. Offline nvcrectl certification render and workloadrun render, which have no cluster to read slices from, take --gpu-arch.
Agents can read certification state over MCP (#372). nvcrectl mcp serve exposes four read-only tools over stdio: list_categories, get_certification_status, get_certification_report, and list_failed_nodes. No tool creates, mutates, or triggers a run, and a test pins that surface so a fifth tool fails the build. Every verdict is projected from the same code that backs nvcrectl certification report, so the two cannot disagree about whether a run passed or which nodes failed.
AWS H100 and GB200 keep the EFA userspace stack (#434). Two override paths matched platform: aws with no GPU guard, so every AWS architecture removed /opt/amazon and unset NCCL_NET_PLUGIN before the workload started. The EFA devices stayed attached and unused while NCCL fell back to TCP over eth0. The cleanup is now scoped to GB300, which is RoCE and has no EFA devices; H100 and GB200 get FI_PROVIDER=efa, FI_EFA_USE_DEVICE_RDMA=1, FI_EFA_FORK_SAFE=1, and IPC_LOCK on both the catalog and WorkloadRun paths.
Certification coverage
- GCP RTX PRO 6000 Blackwell Server Edition overlays for NCCL all-reduce, all-gather, all-to-all, and Nemotron 5 8B, with an eight-GPU architecture default. Smaller G4 node shapes need an explicit
gpusPerNode(#396) - Under KAI Scheduler the MPI launcher gets no
dependsOngate and the JobSet nostartupPolicy, so both sub-groups are populated and the gang is admitted. The ordering barrier moves into the launcher pod, which waits for every worker to answer sshd. Non-KAI paths render byte-identically (#395)
Controller correctness
- Four controllers treated a cache miss as proof a child was deleted and acted on it destructively. Each tier now confirms absence against an uncached reader first, so a Workflow that is still running and still holding GPUs is not written off (#387, #370)
- Bandwidth threshold verdicts are judged on the launcher's complete log, read once when the Job ends, rather than on a partial NCCL size sweep. The rows missed were the largest message sizes, where peak bandwidth is measured, so a healthy group could fail
ThresholdViolationor send adaptive fault isolation down its healthy half (#418) cleanupPVForPVCreads the PVC through the uncached reader. The cached read started a cluster-wide PVC informer the manager role has nowatchfor, so every PVC in the cluster was relisted on a loop after the first cleanup (#425)WorkloadRun.spec.envvalues survive platform overrides that setTrainJob.trainer.env, restoring the documented user-wins precedence (#422)
Measurement and observability
nvcre_certification_statusandnvcre_workflow_statusgauges, with the same 0/1-per-status encoding asnvcre_job_status. A scrape-time collector reads them from the manager's informer cache on the elected leader, so no reconciler write is needed to keep them current (#414)- The ServiceMonitor keeps the controller's own
namespaceandjoblabels instead of letting Prometheus rename them toexported_*, andmetrics.serviceMonitor.labels,.interval, and.scrapeTimeoutare now Helm values. The discovery label was previously hardcoded torelease: prometheus(#413)
Other improvements
nvcrectl certification run --categoryno longer persists the GPU product it detected intospec.target.nodeSelector. Onlynvidia.com/gpu.present: "true"is stored, so node discovery is not pinned to what nodes reported at creation time (#378)--timeoutis validated only when--waitis set, and a value below1sis rejected before the run is created. A tiny or non-positive timeout previously cancelled the watch immediately, which looked like a stalled run (#411)- The release dispatch policy tests exercise the release-tag resolver against a matching tag, a branch ref, and a different tag before crediting its shell guard, and follow local reusable-workflow calls when checking dispatch callers. A guard written as
: # exit 1, or an attest call hidden one hop away, is no longer accepted (#359) - CodeQL analyzes
pull_request, so fork PRs are scanned, and the Fern docs CLI is installed from a lockfile pinned by integrity hash rather thanlatest, which the release publish path resolved at tag time (#393) - Deployment docs cover preloading images when no registry is reachable (#399)
Breaking changes
- The NCCL bandwidth gauges are now
nvcre_nccl_algbw_gbsandnvcre_nccl_busbw_gbs. The previous_gbpsnames incorrectly implied gigabits; the values have always been GB/s from nccl-tests. The old names stay dual-registered as deprecated aliases for one minor release and are removed in the following minor, so a dashboard that is not changed keeps working today but should move to the_gbsnames now (#412) - The ServiceMonitor sets
honorLabels: trueby default. A dashboard built onexported_namespaceorexported_jobstops matching after the chart upgrade; setmetrics.serviceMonitor.honorLabels=falseto keep the previous labels (#413) nodeHealthMonitor,goodputMeasurement, andbandwidthMeasurementon aJobcan no longer be added or removed after creation. Each was already immutable once set; the presence rule closes the absent-to-present and present-to-absent gap. Existing objects are unaffected and an update that does not touch these fields still succeeds, but a patch that adds one of them to a liveJobis now rejected at admission (#402)
Thanks to @asivanadi0, @awolde, @efegokdemir, @gphelps-dev, @kaynetu, @lalitadithya, @MaxFreedomPollard, @mchmarny, @mkjpryor, @ndipebot, @ntheanh201, and @wussh.
Install nvcrectl
The installer is signed. Download it with its bundle, verify, then run — piping it into a shell executes it before anything has checked it.
REL=https://github.com/NVIDIA/cluster-readiness-engine/releases/download/v0.6.0
curl -fsSLO "${REL}/installer"
curl -fsSLO "${REL}/installer.sigstore.json"
cosign verify-blob-attestation \
--bundle installer.sigstore.json \
--type https://slsa.dev/provenance/v1 \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
installer
bash installer -v v0.6.0Without cosign
curl -fsSL https://github.com/NVIDIA/cluster-readiness-engine/releases/download/v0.6.0/installer | bash -s -- -v v0.6.0This runs the installer before anything verifies it. TLS proves you reached GitHub; it proves nothing about the asset if the release itself was tampered with. Use it only where installing cosign first is genuinely impractical.
# newest stable release; `releases/latest` never resolves to a pre-release
curl -fsSL https://github.com/NVIDIA/cluster-readiness-engine/releases/latest/download/installer | bashHelm Chart
This release's chart is published at digest sha256:af20cf1d7827a35e60a539ef9f7fc8445e0def61f345e8bdb030afc76f01f6cf. The signature covers that digest; the version tag is mutable, so verify and install the same digest rather than verifying a digest and installing a tag.
CHART=ghcr.io/nvidia/cluster-readiness-engine
DIGEST=sha256:af20cf1d7827a35e60a539ef9f7fc8445e0def61f345e8bdb030afc76f01f6cf
# 1. Verify the chart. Requires cosign; the package is public, so no login is needed.
cosign verify \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${CHART}@${DIGEST}"
# 2. Pull that exact digest, then install the file you just verified.
helm pull "oci://${CHART}@${DIGEST}"
helm install nvcre ./cluster-readiness-engine@${DIGEST/:/-}.tgz \
--namespace nvcre --create-namespaceInstalling with --version v0.6.0 instead resolves the tag at install time, which is not provably the digest you verified.
helm install --verify does not check this signature. That flag looks for a PGP .prov file, a mechanism unrelated to Sigstore, and we publish no .prov files.
Controller image
A different artifact from the chart, verified separately. The release built and signed these exact digests:
| Subject | Digest |
|---|---|
| index (multi-platform) | sha256:8008c6f9f7e19b317caf0f91afab06b88027c14d7dd03e4173bd49cd1f3cd27a |
linux/amd64 |
sha256:80efd1b6b2ac99b710432c4dbfbeaaf069a6fec53e00bb6894f581e7f0d6f807 |
linux/arm64 |
sha256:1f2ef6945689d10a34e1d6b74f9a6ee52a410698231f317bd1c7d1548df19b98 |
The index carries the signature and the SLSA provenance; each platform digest carries a signature and its own CycloneDX SBOM. Pin the index digest rather than the tag:
IMAGE=ghcr.io/nvidia/cluster-readiness-engine/manager
INDEX=sha256:8008c6f9f7e19b317caf0f91afab06b88027c14d7dd03e4173bd49cd1f3cd27a
cosign verify \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${IMAGE}@${INDEX}"nvcrectl CLI
Download the binary for your platform from the assets below and place it on your $PATH.
| Platform | Binary |
|---|---|
| Linux amd64 | nvcrectl-linux-amd64 |
| Linux arm64 | nvcrectl-linux-arm64 |
| macOS amd64 | nvcrectl-darwin-amd64 |
| macOS arm64 (Apple Silicon) | nvcrectl-darwin-arm64 |
Verify your download
Every asset ships with a Sigstore bundle, <asset>.sigstore.json, carrying a SLSA Build Provenance v1 statement. Verify the artifact itself, not a checksum served from the same place as the artifact:
REL=https://github.com/NVIDIA/cluster-readiness-engine/releases/download/v0.6.0
ASSET=nvcrectl-linux-amd64 # or installer, or any published asset
# The bundle is a separate asset; fetch both.
curl -fsSLO "${REL}/${ASSET}"
curl -fsSLO "${REL}/${ASSET}.sigstore.json"
cosign verify-blob-attestation \
--bundle "${ASSET}.sigstore.json" \
--type https://slsa.dev/provenance/v1 \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${ASSET}"Each nvcrectl-* binary also ships a CycloneDX SBOM, <binary>.cyclonedx.json. There are two bundles involving it, one segment apart in name, and they prove different things:
| Bundle | Proves |
|---|---|
<binary>.cyclonedx.json.sigstore.json |
the SBOM file is the one we published and was not altered |
<binary>.cyclonedx.sigstore.json |
the SBOM describes that binary — it is bound to the binary as its subject |
Before feeding an SBOM to a scanner, check both. The binding proves an SBOM describes the binary; it says nothing about the bytes of the file on your disk, which is a separate download.
cosign verify-blob-attestation \
--bundle "${ASSET}.cyclonedx.sigstore.json" \
--type cyclonedx \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${ASSET}"
# 2. the SBOM file you downloaded is the one that was published
cosign verify-blob-attestation \
--bundle "${ASSET}.cyclonedx.json.sigstore.json" \
--type https://slsa.dev/provenance/v1 \
--certificate-identity "https://github.com/NVIDIA/cluster-readiness-engine/.github/workflows/attest.yml@refs/tags/v0.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${ASSET}.cyclonedx.json"Only the first would let a tampered local .cyclonedx.json reach your scanner: the binding attestation carries its own copy of the SBOM and never looks at your file.
checksums.txt is still published and still works, but it is not the verification story: it is served from the same origin as the assets and is itself unsigned, so it detects corruption rather than tampering.
sha256sum --check --ignore-missing checksums.txtThird-Party Notices
Third-party Go module licenses are listed in THIRD_PARTY_NOTICES.md and attached as a release asset.
Support
- Ask questions in GitHub Discussions.
- Report bugs with the issue templates.
- Report security issues per SECURITY.md, never through GitHub issues.
What's Changed
Dependency Updates
- build(deps): bump anchore/sbom-action from 0.24.2 to 0.24.3 in the actions group by @dependabot[bot] in #431
Other Changes
- fix(controller): prevent false WorkloadRun failure on Workflow cache miss by @kaynetu in #370
- chore(fern): register v0.5.0 by @github-actions[bot] in #382
- ci: resolve the actionable code-scanning alerts by @ndipebot in #393
- fix(cli): stop persisting detected GPU product into Certification nodeSelector by @mkjpryor in #378
- fix(controller): confirm a missing child against the API server before acting on it by @ndipebot in #387
- fix(controller): judge bandwidth on the complete final log, never a partial sweep by @mchmarny in #418
- feat: add GCP RTX PRO 6000 NVCRE overlays by @awolde in #396
- chore: add e2e tests by @lalitadithya in #427
- test: exercise release ref guards and follow attest wrappers by @MaxFreedomPollard in #359
- fix(cli): validate --timeout only with --wait, floor at 1s by @asivanadi0 in #411
- fix(metrics): rename NCCL bandwidth gauges to GB/s-accurate names by @asivanadi0 in #412
- fix(helm): honor metric labels on ServiceMonitor and expose scrape knobs by @asivanadi0 in #413
- fix: preserve WorkloadRun user env precedence by @efegokdemir in #422
- docs: add ADR-086 for lifecycle status metrics and timeout exclusivity by @kaynetu in #423
- fix(controller): read the PVC in cleanupPVForPVC from the API server by @gphelps-dev in #425
- feat: resolve GPU architecture without the nvidia.com/gpu.product label by @mkjpryor in #379
- feat(mcp): add a read-only MCP server for certification state by @ntheanh201 in #372
- fix(mpi): admit the KAI gang by dropping the launcher gate and waiting in the pod by @wussh in #395
- docs(deployment): preloading images when no registry is reachable by @wussh in #399
- fix(api): enforce presence immutability for optional JobSpec fields by @efegokdemir in #402
- feat(metrics): scrape Certification and Workflow status from the informer cache by @asivanadi0 in #414
- fix: keep the EFA stack for AWS H100 and GB200 on both the catalog and WorkloadRun paths by @ndipebot in #434
- docs: prepare the v0.6.0 release by @ndipebot in #435
New Contributors
- @mkjpryor made their first contribution in #378
- @awolde made their first contribution in #396
- @MaxFreedomPollard made their first contribution in #359
- @efegokdemir made their first contribution in #422
- @gphelps-dev made their first contribution in #425
- @wussh made their first contribution in #395
Full Changelog: v0.5.0...v0.6.0