feat: add GPU spot instance support for Azure node pools #1837 - #1870
Conversation
TitleAdd Azure GPU Spot Instance Support Description
Changes walkthrough 📝
|
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
| operator: "Equal" | ||
| value: "gpu" | ||
| effect: "NoSchedule" | ||
| {{- if .Values.spotInstance.enabled }} |
There was a problem hiding this comment.
I think it doesnt hurt to add this toleration without toggle?
There was a problem hiding this comment.
Agree at the end customer could use node labels/selectors. And Spot instances are legitimate target for running AI models.
|
If you check the issue, we would also need to add toleration in the sts pod template otherwise, the pod cannot use the spot gpu. |
|
@zeel2104, the toleration we add is specific for azure. Please add a guard in both yaml and controller to add the toleration for azure cloud provider only. |
Oh good point. KAITO is meant to be multi-provider and the Spot tolerations might be different across different providers. At the end may be it is good to add an input variable in values.yaml for 'custom'/provider-specific tolerations. |
|
@Fei-Guo Validation:
|
andyzhangx
left a comment
There was a problem hiding this comment.
this PR makes it possible to run KAITO workspace on existing spot node pool, that's BYO node scenario, I think you need to mention this in PR description.
Moreover, shall we consider adding spot node pool support in node auto-provisioning scenario?
| # Set enabled: true to allow workloads to be scheduled on Azure Spot nodes. | ||
| # This adds the required toleration for Azure Spot node pools. | ||
| spotInstance: | ||
| enabled: false |
There was a problem hiding this comment.
just set default as true since it would be easier to covered in e2e test and no harm if it's supporting spot by default?
There was a problem hiding this comment.
Pull request overview
Adds Azure Spot GPU support by introducing the required tolerations so KAITO components can run on Azure Spot-tainted node pools, reducing GPU cost/pressure for dev and production clusters.
Changes:
- Adds Azure Spot toleration constants and cloud-provider detection helper.
- Updates inference/tuning pod generation to include Azure Spot toleration.
- Adds Helm
spotInstance.enabledvalue to conditionally tolerate Spot taint for the NVIDIA device plugin DaemonSet.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/workspace/tuning/preset_tuning.go | Builds default tolerations (now includes Azure Spot) and switches output dir path handling. |
| pkg/workspace/tuning/preset_tuning_test.go | Adds unit test coverage for default tolerations behavior. |
| pkg/workspace/inference/template_inference.go | Uses computed default tolerations when generating template inference manifests. |
| pkg/workspace/inference/preset_inferences.go | Builds default tolerations (now includes Azure Spot) for inference pods. |
| pkg/workspace/inference/preset_inferences_test.go | Adds unit test coverage for default tolerations behavior. |
| pkg/utils/consts/consts.go | Introduces constants for Azure Spot taint key/value. |
| pkg/utils/common.go | Adds IsAzureCloudProvider() helper based on CLOUD_PROVIDER. |
| charts/kaito/workspace/values.yaml | Adds spotInstance.enabled Helm value with documentation. |
| charts/kaito/workspace/templates/nvidia-device-plugin-ds.yaml | Conditionally adds Azure Spot toleration to the device plugin DaemonSet. |
Comments suppressed due to low confidence (1)
pkg/workspace/tuning/preset_tuning.go:103
PrepareOutputDirintends to constrainoutputDirunder/mnt, but the current prefix check is not path-boundary safe (e.g.,/mntxpassesHasPrefix("/mnt")). This can allow paths outside the intended base directory. Use a boundary-aware check (e.g., require/mnt/prefix) or compute apath.Relto ensure the cleaned path does not escape the base dir.
cleanPath := outputDir
if !strings.HasPrefix(cleanPath, DefaultBaseDir) {
cleanPath = path.Join(DefaultBaseDir, outputDir)
}
cleanPath = path.Clean(cleanPath)
if cleanPath == DefaultBaseDir || !strings.HasPrefix(cleanPath, DefaultBaseDir) {
klog.InfoS("Invalid output_dir specified: '%s', must be a directory. Using default output_dir: %s", outputDir, DefaultOutputVolumePath)
return DefaultOutputVolumePath, fmt.Errorf("invalid output_dir specified: '%s', must be a directory", outputDir)
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if utils.IsAzureCloudProvider() { | ||
| tolerations = append(tolerations, corev1.Toleration{ | ||
| Effect: corev1.TaintEffectNoSchedule, | ||
| Key: consts.SpotInstanceKey, | ||
| Operator: corev1.TolerationOpEqual, | ||
| Value: consts.SpotInstanceValue, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Spot toleration is added for all Azure clusters purely based on CLOUD_PROVIDER, regardless of whether the user opted into Spot support. This can unintentionally allow inference pods to land on Spot GPU node pools when both Spot and on-demand pools exist, which conflicts with the Helm-level spotInstance.enabled flag and the PR description’s “opt-in” behavior. Consider gating this behind an explicit setting (e.g., env var wired from Helm values, a Workspace spec field, or a feature gate) rather than cloud-provider detection alone.
| if utils.IsAzureCloudProvider() { | ||
| tolerations = append(tolerations, corev1.Toleration{ | ||
| Effect: corev1.TaintEffectNoSchedule, | ||
| Key: consts.SpotInstanceKey, | ||
| Operator: corev1.TolerationOpEqual, | ||
| Value: consts.SpotInstanceValue, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Spot toleration is added for all Azure clusters purely based on CLOUD_PROVIDER, not an explicit opt-in. This can broaden scheduling to Spot GPU node pools even when users did not enable Spot support (and Helm’s spotInstance.enabled currently only affects the device plugin DaemonSet). Consider guarding this behind an explicit configuration flag that’s plumbed into the controller/workspace generation path.
| # Set enabled: true to allow workloads to be scheduled on Azure Spot nodes. | ||
| # This adds the required toleration for Azure Spot node pools. |
There was a problem hiding this comment.
The spotInstance.enabled comment says it “allow[s] workloads to be scheduled on Azure Spot nodes”, but this chart value only toggles an extra toleration on the nvidia-device-plugin DaemonSet. Consider clarifying the wording to reflect what it actually affects (device plugin scheduling), and/or document how workspace pods opt into Spot toleration (if that’s intended to be separate).
| # Set enabled: true to allow workloads to be scheduled on Azure Spot nodes. | |
| # This adds the required toleration for Azure Spot node pools. | |
| # Set enabled: true to add the required toleration to the NVIDIA device plugin | |
| # DaemonSet so it can run on Azure Spot node pools. Workspace pods must opt | |
| # into Azure Spot toleration separately if they also need to run on Spot nodes. |
| cleanPath = filepath.Clean(cleanPath) | ||
| cleanPath = path.Clean(cleanPath) | ||
| if cleanPath == DefaultBaseDir || !strings.HasPrefix(cleanPath, DefaultBaseDir) { | ||
| klog.InfoS("Invalid output_dir specified: '%s', must be a directory. Using default output_dir: %s", outputDir, DefaultOutputVolumePath) |
There was a problem hiding this comment.
klog.InfoS does not apply printf-style formatting; the %s placeholders will be logged literally. Switch to structured logging (message + key/value pairs) or use klog.Infof if formatting is desired.
| klog.InfoS("Invalid output_dir specified: '%s', must be a directory. Using default output_dir: %s", outputDir, DefaultOutputVolumePath) | |
| klog.InfoS("Invalid output_dir specified, using default output_dir", "outputDir", outputDir, "defaultOutputDir", DefaultOutputVolumePath) |
Reason for Change:
GPU instances are expensive and have limited quota. This PR adds support for running KAITO workloads on Azure Spot GPU node pools to reduce costs in both dev and production environments.
Requirements
[X] added unit tests and e2e tests (if applicable).
Issue Fixed:
Fixes #1837
Notes for Reviewers:
-> Added a spotInstance.enabled flag to values.yaml (defaults to false, no breaking change for existing users)
-> When enabled, adds the kubernetes.azure.com/scalesetpriority=spot:NoSchedule toleration to the nvidia-device-plugin DaemonSet so it can be scheduled on Spot node pools
-> The workspace Deployment already supports tolerations dynamically via Values.tolerations so no changes needed there
-< To enable spot support, users simply set spotInstance.enabled: true in their values override
-> No existing Helm tests found in the chart. Validated via helm lint and helm template --set spotInstance.enabled=true dry-ruN