Release v1.31.0
This release adds Akamai Cloud (LKE) support to janitor-provider and csp-health-monitor, adds IPv6 support, and lets janitor stop GPU clients outside the GPU Operator and patch the GPU reset Job. A new default fault-quarantine rule set cordons nodes for fatal health-events-analyzer events. It also fixes several PostgreSQL change-stream problems, stops a GPU reset that a retry recovers from rebooting the node, and keeps fault-quarantine running on a cluster with no GPU nodes.
Note
DCGM 3.x support in GPU Health Monitor is deprecated. It will be removed on 30 November 2026. DCGM 3.x is end-of-life and gets no more patches. After the removal, NVSentinel does not detect faults on nodes that run DCGM 3.x. To find these nodes, run kubectl get nodes -l nvsentinel.dgxc.nvidia.com/dcgm.version=3.x. Upgrade DCGM on these nodes to 4.x before you upgrade to the release that removes DCGM 3.x support. For the steps in each global.dcgm.mode, see GPU Health Monitor: DCGM 3.x Support Removal. To give feedback, comment on #2102.
Upgrade Notes
Fault-quarantine rule set for health-events-analyzer events (#2335, #2297)
health-events-analyzer publishes fatal derived events, such as MultipleRemediations and RepeatedXID74Reg0HardwareIssue. No default fault-quarantine rule set matched them, so these events set node conditions but did not cordon, drain or remediate the node. The new default rule set Health events analyzer fatal error ruleset cordons the node for a fatal health-events-analyzer event. This is a change to the default of fault-quarantine.ruleSets. helm upgrade --reuse-values keeps your previous rule sets. If you run health-events-analyzer and want these events to quarantine nodes, upgrade with --reset-then-reuse-values (Helm 3.14 or later). It keeps your own values and applies the new chart defaults. If you set your own ruleSets, copy the rule set from the v1.31.0 chart.
XID 74 rules in health-events-analyzer (#2271, #2270)
The four XID 74 solo rules took their registers and their GPU from the node's stored events, not from the incoming XID 74 event. After one matching XID 74 on a GPU, every later XID 74 on the node fired the rule, and the CONTACT_SUPPORT event could name a GPU whose registers did not match, or a GPU that was not solo. The rules now read the registers and the GPU from the incoming event. The fix is in the default value of health-events-analyzer.config. helm upgrade --reuse-values keeps your previous value. If you run health-events-analyzer, upgrade with --reset-then-reuse-values. If you set your own config, copy the four XID 74 solo rules from the v1.31.0 chart.
Major New Features
Akamai Cloud (LKE) Support (#2114, #2115)
NVSentinel now supports Akamai Cloud (Linode Kubernetes Engine, LKE):
- janitor-provider (#2114): with
janitor-provider.csp.provider: akamai, janitor reboots and replaces nodes through the Akamai Cloud API. A reboot is complete when the instance isrunningand the kubelet reports a new boot ID. A terminate recycles an LKE node, so LKE provisions a replacement and the node pool keeps its size. An instance outside LKE is deleted. The provider acts only on a node with alinode://<id>provider ID. Set the API token Secret injanitor-provider.csp.akamai.apiTokenSecretRef. The token needs thelinodes:read_writeandlke:read_writescopes. - csp-health-monitor (#2115): with
csp-health-monitor.cspName: akamai, the monitor polls the Akamai account maintenance API and quarantines and drains a node before its maintenance starts. Every maintenance type quarantines the node,live_migrationincluded, because a GPU workload cannot live-migrate. The poll interval isconfigToml.akamai.pollingIntervalSeconds, default60, minimum30. Set the token Secret incsp-health-monitor.akamaiApiTokenSecret. The token needs theaccount:read_onlyscope.
These scopes cover the whole Akamai account, so use a dedicated token for NVSentinel.
IPv6 Support (#2252)
Set global.ipv6.enabled: true to run NVSentinel on an IPv6-only or dual-stack cluster. The default is false. With the flag on, gpu-health-monitor binds its metrics server to ::, Bitnami MongoDB sets MONGODB_ENABLE_IPV6, Percona MongoDB adds net.ipv6: true to the default replica set configuration, and the in-cluster file server also listens on [::]:8080. Every node must boot with IPv6 on. Also set the GPU Operator's DCGM host engine to bind :: with dcgm.args in the GPU Operator chart, which needs GPU Operator v26.7.1 or later. If DCGM binds only 0.0.0.0, the labeler sets no DCGM version label, and gpu-health-monitor schedules no pods.
With helm upgrade --reuse-values, the Percona replica set configuration keeps its previous value. To turn on IPv6 with the Percona backend, upgrade with --reset-then-reuse-values. If you set your own mongodb-store.psmdb-db.replsets.rs0.configuration, add net.ipv6: true to it.
GPU Reset Stops GPU Clients Outside the GPU Operator (#2276, #1691)
A GPU client that runs outside the GPU Operator namespace, for example a monitoring agent, keeps the GPUs open, and nvidia-smi --gpu-reset fails with In use by another client. GPU Operator 26.7 and later sets the nvidia.com/gpu.deploy.client=true node label, and GPU clients select it. Before a GPU reset, janitor now sets this label to false when at least one GPU client pod runs on the node. It waits until the DaemonSet controller removes the GPU client pods, and sets the label back to true after the reset. NVSentinel's metadata-collector selects this label too, so it also leaves the node during the reset. The janitor ClusterRole gains get on DaemonSets.
GPU Reset Job Patch (#2324, #1782)
The new janitor.config.controllers.gpuReset.resetJob.jobTemplatePatch value is a strategic merge patch that janitor applies on top of the built-in GPU reset Job, so you can change the Job without forking janitor. janitor always sets the Job name, namespace, owner reference and node name, and the NVIDIA_GPU_RESETS variable of each container, itself. janitor refuses at startup a patch with a misspelled field, a field in the wrong case or a value of the wrong type. Init containers now also get NVIDIA_GPU_RESETS. The patch is empty by default. The janitor configuration docs give the merge rules and an example.
Mount Only the Journal Directory (#2292, #2291)
The new syslog-health-monitor.journalDirectoryHostPath value mounts only the host journal directory in regular mode, in place of its parent in journalHostPath. Use it where a vcluster syncer rewrites a /var/log host path to a per-tenant directory, which hides the journal. The directory must exist on every node. The value is empty by default.
Metrics
metadata_collector_collection_completed_timestamp_seconds(#2157): a new gauge. It is0until GPU metadata collection completes, and then holds the completion time. To find a collector that is stuck, alert onmetadata_collector_collection_completed_timestamp_seconds == 0 and time() - process_start_time_seconds > 300.fault_quarantine_get_total_nodes_retry_attemptsis removed (#2273, #2272): fault-quarantine no longer retries a GPU node count of 0. Remove dashboards and alerts that use this metric.- External remediation metrics (#2161):
nvsentinel_external_remediation_total{phase="closed"}gains theresultvaluenode_deleted, for a request whose Node is missing, terminating or replaced.nvsentinel_external_remediation_openis now set to0or1, and janitor restores it after a restart.
Bug Fixes & Reliability
- A GPU reset that a retry recovers does not reboot the node (#2254, #2279): the reset Job runs
gpu_reset.shagain after a failed run, and every run wrote its result to syslog. When the first run failed and the retry reset the GPU, syslog-health-monitor had already requested a reboot for the first failure. The reset Job now reports a failed reset only from its last run. When the last run fails, the node still reboots. - Node patches retry after a connection error (#2267, #2266): a node patch whose connection failed before the response, for example when the API server restarted, was not retried. In fault-quarantine, this was the cordon of a fatal event, so the event was checkpointed and the node stayed schedulable until fault-quarantine restarted. The node patches of fault-quarantine, the labeler and lifecycle-manager now retry connection resets, unexpected EOFs, lost HTTP/2 connections and refused connections, with the existing backoff of 10 attempts.
- Fault-quarantine runs on a cluster with no GPU nodes (#2273, #2272): the circuit breaker treated a GPU node count of 0 as a cache sync failure, retried, and then made fault-quarantine exit, so fault-quarantine crash-looped. With no GPU nodes, the breaker now reports
CLOSED. If a cordon is recorded in the window while the breaker counts 0 GPU nodes, the breaker trips, becausefault-quarantine.gpuNodeLabelthen does not match the nodes that fault-quarantine cordons. - An escalated recommended action stays in the quarantine annotation (#2163, #2162): when a later event escalated the
RecommendedActionof a stored event, fault-quarantine overwrote some keys of the older compound event without compacting the stored events. The older event still listed those entities, so a JSON round trip of the annotation could restore the older action. Fault-quarantine now compacts the stored events whenever it overwrites an entry. - PostgreSQL change stream (#2231, #2153, #2250, #2249, #2265, #2264): with the PostgreSQL datastore:
- The event filter did not support
$exists. Every event that was notEXECUTE_REMEDIATIONloggedUnsupported operator, and fault-quarantine and health-events-analyzer dropped events with no processing strategy, which MongoDB delivers. The filter now supports$exists. - When the
changed_atlookup of an acknowledged event failed, the watcher saved the current time as its resume position, so a restart skipped events. The watcher now returns an error and keeps its position. - The cursor moved only to a row with a higher id. A row with a higher id but an earlier
changed_atmade every later poll return the same rows, and with 100 or more such rows the consumer stopped. The cursor now moves forward in(changed_at, id)order.
- The event filter did not support
- Datastore clients wait for MongoDB to start (#2245, #2140): the chart set
MONGODB_PING_TIMEOUT_TOTAL_SECONDSto30, so platform-connectors, fault-quarantine, node-drainer and fault-remediation gave up after about 35 seconds while MongoDB started, and restarted. The chart no longer sets it, so these components use the store-client default of 300 seconds. The same setting also sets the MongoDB server selection timeout, the resume token store retry window and the change stream recovery pass, which also change from 30 to 300 seconds. - External remediation requests stay open until the repair completes (#2125, #2072, #2161): janitor started the ExternalRemediationRequest TTL at the first reconcile. With the default TTL of
336h, a repair that took longer than 14 days lost its release taint and itsnvsentinel.dgxc.nvidia.com/managed=falselabel, and NVSentinel took the node back during the repair. The TTL now starts when the request completes, so the TTL never deletes an open request. janitor also checks the Node UID before it applies or cleans up a request, matches the release taint by key, effect and request name, and keeps taints that operators or other requests own. The newCompletedRequestDeletedandOwnerNodeDeletedevents report when a completed request is deleted and when a Node deletion closes an open request. - Generic reboot Jobs end with their attempt (#2178, #2177, #2300): janitor-provider deleted its reboot Job only when the node came back with a new boot ID. When janitor gave up on a RebootNode, the Job stayed, its pod could reboot the node later, and a leftover pod in
ImagePullBackOfffailed each later RebootNode for that node. janitor-provider now deletes the old reboot Jobs before it starts an attempt and when an attempt fails, and reads only the pods of the current Job. When the kubelet rejects the reboot pod at admission, for example asEvictedunder disk pressure, the attempt now fails at the next readiness check instead of at the reboot timeout. - XID detection continues past invalid UTF-8 (#2269, #2268): the
name=field of a kernel XID line can hold bytes that are not valid UTF-8. The health event built from such a line could not be encoded, so the publish failed, and the XID check stopped at that line on every poll, restarts included. syslog-health-monitor now replaces such bytes with U+FFFD. - The post-reboot scan reads the current boot (#2298, #2277): the scan that reads the journal entries written before syslog-health-monitor started compared the journal
_BOOT_ID, which has no dashes, with the boot ID in/proc, which has dashes. Nothing matched, so the scan skipped every entry of the current boot, and XIDs logged before the monitor started were missed. The comparison now ignores the field name and the dashes. - XID 74 derived events name the reporting GPU (#2271, #2270): see the Upgrade Notes.
- metadata-collector memory (#2251, #2176): the pod device mapper decoded the whole kubelet
/podsresponse every 30 seconds. On nodes with large finished pods, metadata-collector exceeded its memory limit and was OOM-killed in a loop. It now decodes one pod at a time, so its memory no longer grows with the size of the pod specs. - metadata-collector serves metrics during collection (#2157): metadata-collector started its metrics server only after GPU metadata collection finished, so a collector blocked on a hung driver served no metrics. The metrics server now starts first. See Metrics for the new completion gauge.
- metadata-collector permission for fine-grained kubelet authorization (#2328, #2323): the metadata-collector ClusterRole had no
getonnodes/pods, so under fine-grained kubelet authorization, each/podspoll made a denied access review before the kubelet fell back tonodes/proxy. The ClusterRole now grantsgetonnodes/pods. - nccl-loopback preflight check (#2259, #2258, #2261, #2260): the check reported a fatal
NCCL_TEST_ERRORagainst healthy nodes in two cases. On RTX Pro 6000 (sm_120), the image had nosm_120kernels, and it now builds them. When the workload setNCCL_DEBUG=INFO, NCCL log lines broke the result table, and the check now sends the NCCL log to stderr.
Security & Infrastructure
- CVE fixes (#2337): the gpu-reset image installs the latest Ubuntu security fixes for curl and its libraries, and the log-collector image moves to kubectl v1.35.10.
Documentation
- Metrics reference (#2326, #2280):
docs/METRICS.mdnow lists 92 metrics that were missing across 16 components, and corrects 12 entries, including the_totalsuffix of 11 gpu-health-monitor counters and thedrain_scopelabel ofnode_drainer_events_processed_total. datastore_connected(#2243): the metrics reference and the HELP text now say that the gauge becomes1when the datastore watcher starts, and stays1for the life of the process. To detect a datastore problem, alert on pod readiness (kube_pod_status_ready) and restarts.GangSchedulinggate on Kubernetes 1.37 (#2319): Kubernetes 1.37 removed theGangSchedulingfeature gate, and kube-scheduler does not start with an unknown gate. The README andvalues-preflight-kube.yamlnow ask for the gate only on Kubernetes 1.35 and 1.36.
Chores
- E2E conflict retries (#2202, #2138, #2310, #2307): E2E test helpers failed with HTTP 409 when NVSentinel components updated the same Node. The new
helpers.ConflictBackofftries 10 times in about 7.5 seconds, and replacesretry.DefaultRetryin all 30 places intests/. The cordon-patch connection-reset test now accepts every retryable error, including an unexpected EOF over HTTP/2. - Network retries in CI (#2242, #2246, #2142): one failed network call failed a CI job. CI now runs
apt-get,go install,pip installand the other network downloads that failed jobs throughscripts/retry.sh, up to 3 times, and the Dockerfiles retrygo mod download. - Image builds on native runners (#2285, #2283): Container Build Validation built the arm64 images in QEMU emulation, and the
preflight-nccl-loopbackjob reached its 45-minute limit. Each architecture now builds on its own runner, and the two builds run in parallel. - Contributor guidance (#2253, #2120):
AGENTS.mdadds the rules that the CI reliability work showed, for example how to retry conflicts in E2E tests, how to show that a flake is fixed, and how to list a new E2E test intests/e2e-shards.yaml.
Acknowledgments
This release includes contributions from:
- @akhil9tiet
- @blacksoxx
- @cbaenziger
- @cbumb
- @dcandido-dot
- @deesharma24
- @eexwhyzee
- @glassharbor
- @jianzhangbjz
- @JSJANG552
- @jtschelling
- @karanaggarwal1
- @kdotmanoj
- @lalitadithya
- @nsd9696
- @patelpayal
- @pcbeingused333
- @Saibernard
- @sumedh-aerram
- @TheVicky1
- @XRFXLP
- @yuminn-k
- @ZeXi0308
Thank you to everyone who contributed code, testing, documentation, design reviews, and feedback! Special thanks to first-time contributors @cbaenziger, @dcandido-dot, @eexwhyzee, @glassharbor, @JSJANG552, @karanaggarwal1, @nsd9696, @patelpayal, @pcbeingused333, @sumedh-aerram, @TheVicky1, and @yuminn-k.
Container Images
See versions.txt for the full list of container images and versions.
Helm Chart
Install with:
helm install nvsentinel oci://ghcr.io/nvidia/nvsentinel \
--version v1.31.0 \
--namespace nvsentinel \
--create-namespaceTo upgrade from v1.30.0 — review the Upgrade Notes above first:
helm upgrade nvsentinel oci://ghcr.io/nvidia/nvsentinel \
--version v1.31.0 \
--namespace nvsentinel \
--reuse-values