Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ resources:
kind: NVIDIADriver
path: github.com/NVIDIA/gpu-operator/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
controller: true
domain: com
group: nvidia
kind: GPUCluster
path: github.com/NVIDIA/gpu-operator/api/v1alpha1
version: v1alpha1
version: "3"
181 changes: 181 additions & 0 deletions api/nvidia/v1alpha1/gpucluster_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**
# Copyright (c) NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
**/

package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

nvidiav1 "github.com/NVIDIA/gpu-operator/api/nvidia/v1"
)

const (
GPUClusterCRDName = "GPUCluster"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the GPUCluster controller passes it to state.NewManager. I can remove if preferred, no strong preference here

)

const (
// Ignored marks a duplicate GPUCluster that the singleton controller does not reconcile.
Ignored State = "ignored"
)

// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// GPUClusterSpec defines the desired state of GPUCluster, the DRA-based
// software-enablement stack. Unlike ClusterPolicy, it does not manage the NVIDIA driver
// or the device-plugin; the driver is installed separately (host-installed or via an
// NVIDIADriver CR) and GPUCluster waits for driver readiness before proceeding.
type GPUClusterSpec struct {
// DRADriver defines the spec for the NVIDIA DRA driver stack (gpus + computeDomains).
DRADriver DRADriverSpec `json:"draDriver"`

// DCGM defines the spec for the standalone NVIDIA DCGM hostengine. Disabled by default;
// when disabled, dcgm-exporter uses its embedded nv-hostengine. NOTE: the reused enabled
// field carries no server-side default and its IsEnabled() treats nil as enabled, so the
// controller must default nil enabled to disabled here.
DCGM *nvidiav1.DCGMSpec `json:"dcgm,omitempty"`
Comment thread
tariq1890 marked this conversation as resolved.

// DCGMExporter defines the spec for NVIDIA DCGM Exporter. Enabled by default, but the
// reused enabled field carries no server-side default; the controller defaults nil enabled.
DCGMExporter *nvidiav1.DCGMExporterSpec `json:"dcgmExporter,omitempty"`

// HostPaths defines the host paths used in host-path volumes for various components.
HostPaths nvidiav1.HostPathsSpec `json:"hostPaths,omitempty"`

// Daemonsets defines the common configuration applied to all DaemonSets deployed
// by the GPUCluster controller.
Daemonsets nvidiav1.DaemonsetsSpec `json:"daemonsets,omitempty"`
}

// DRADriverSpec defines the spec for the NVIDIA DRA driver stack. There is no top-level
// enabled toggle; the gpus capability is always deployed and computeDomains has its own
// enabled field.
type DRADriverSpec struct {
// NVIDIA DRA driver image repository
Repository string `json:"repository,omitempty"`

// NVIDIA DRA driver image name
// +kubebuilder:validation:Pattern=^[a-zA-Z0-9\-]+$
Image string `json:"image,omitempty"`

// NVIDIA DRA driver image tag
Version string `json:"version,omitempty"`

// Image pull policy
ImagePullPolicy string `json:"imagePullPolicy,omitempty"`

// Image pull secrets
ImagePullSecrets []string `json:"imagePullSecrets,omitempty"`

// FeatureGates is a map of feature gate names to a boolean enabling or disabling each.
// It is rendered as the FEATURE_GATES environment variable on the DRA driver containers.
FeatureGates map[string]bool `json:"featureGates,omitempty"`

// GPUs configures the gpu.nvidia.com capability of the DRA driver.
GPUs DRADriverGPUsSpec `json:"gpus,omitempty"`

// ComputeDomains configures the compute-domain capability of the DRA driver.
ComputeDomains DRADriverComputeDomainsSpec `json:"computeDomains,omitempty"`
}

// IsComputeDomainsEnabled returns true if the computeDomains capability of the DRA driver is enabled.
func (d *DRADriverSpec) IsComputeDomainsEnabled() bool {
return d.ComputeDomains.Enabled != nil && *d.ComputeDomains.Enabled
}

// DRADriverGPUsSpec configures the gpus capability of the DRA driver. It maps onto the
// gpus container of the upstream kubelet-plugin DaemonSet. The capability is always
// deployed; there is no enabled toggle.
type DRADriverGPUsSpec struct {
// KubeletPlugin configures the kubelet-plugin workload for the gpus capability.
KubeletPlugin DRADriverKubeletPluginSpec `json:"kubeletPlugin,omitempty"`
}

// DRADriverComputeDomainsSpec configures the computeDomains capability of the DRA driver.
// The kubeletPlugin maps onto the computeDomains container of the upstream kubelet-plugin
// DaemonSet; the controller is a separate Deployment.
type DRADriverComputeDomainsSpec struct {
// Enabled indicates if the computeDomains capability of the DRA driver is enabled.
// +kubebuilder:default=true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shivamerla are you okay if we enable compute domains by default?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in Slack, we will enable compute domains by default.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karthikvetrivel this is how it is deployed with the helm chart though there is no good justification of it running when there are no MNNVL systems in the cluster (atleast not yet!).

The idea is that customers can create ComputeDomain instances regardless of the cluster's topology and schedule their workloads without having to reason about the actual node layout. The CD plugin auto-detects fabric vs. non-fabric nodes and simply skips IMEX management on the non-fabric ones. Later, if a user introduces an MNNVL system into the cluster and some workload replicas happen to land there, the already-running CD plugin will pick that up automatically and form an IMEX domain around the new system, since the same resource claim template is shared across all the claims of the workload's replicas. Though AFAIK, for multi-node workloads (inference/training) it is always recommended to run with homogeneous GPU types. So need some real customer feedback on this use case.

For clarity, here are the pros and cons of enabling this when there's no MNNVL system in the cluster.

Pros:

  • As mentioned above, workloads can span multiple racks without topology constraints and seamlessly adopt any MNNVL system that gets added later. Otherwise, users would have to delete the workload and re-bind it to a ComputeDomain after the fact (using its auto-generated resource claim template).
  • Less operational overhead, admins don't have to go read the docs and explicitly turn this on whenever a new MNNVL system shows up in the cluster.

Cons:

  • An extra CD controller pod gets deployed, along with a sidecar plugin container. Depending on the cluster scale, this added footprint may or may not matter.
  • The controller pod sets up informers on ComputeDomain, CDClique, DaemonSets, Pods, and Nodes, and the kubelet plugin sets up an informer on ComputeDomain. That said, with no actual CR instances created, this should stay lightweight.
  • An extra resource slice is created to advertise channel and daemon devices, which could be confusing to users.
  • An extra device class is created for channel allocations.
  • Any change to the CD plugin config triggers a rollout of the GPU plugin too, since both ship within a single DaemonSet.
  • For OLM-based deployments, the webhook configuration has to be embedded in the CSV, so it ends up intercepting every ResourceClaim creation, even in cases where the CD plugin isn't actually being used.

I don't see any user feedback on this yet on the DRA side as well, so we have to make a judgement based on the above factors. The operator could also be smart and enable it (i.e actually create a deployment, plugin sidecar) only when it sees a MNNVL capable node in the cluster. There could be a sub-option in the CR under cdPlugin to control this behavior. If users really want to use ComputeDomain CR prior to adding capable systems, then they can use this sub-option to let it deploy always.

Enabled *bool `json:"enabled,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a *bool instead of just bool? Are we trying to differentiate between unset and set (true/false)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, yes.


// Controller configures the compute-domain controller Deployment.
Controller DRADriverControllerSpec `json:"controller,omitempty"`

// KubeletPlugin configures the kubelet-plugin workload for the computeDomains capability.
KubeletPlugin DRADriverKubeletPluginSpec `json:"kubeletPlugin,omitempty"`
}

// DRADriverKubeletPluginSpec configures a DRA driver kubelet-plugin container. The gpus and
// computeDomains blocks map onto the two containers of a single kubelet-plugin DaemonSet.
// Scheduling is opinionated and not configurable here.
type DRADriverKubeletPluginSpec struct {
// Optional: List of environment variables
Env []nvidiav1.EnvVar `json:"env,omitempty"`

// Optional: Define resources requests and limits for the kubelet-plugin container
Resources *nvidiav1.ResourceRequirements `json:"resources,omitempty"`

// HealthcheckPort is the port of the container's gRPC health service, checked by the
// startup and liveness probes. Set to a negative value to disable the probes.
HealthcheckPort *int32 `json:"healthcheckPort,omitempty"`
}

// DRADriverControllerSpec defines configuration for the compute-domain controller Deployment.
// Scheduling is opinionated and not configurable here.
type DRADriverControllerSpec struct {
// Optional: List of environment variables
Env []nvidiav1.EnvVar `json:"env,omitempty"`

// Optional: Define resources requests and limits for the controller container
Resources *nvidiav1.ResourceRequirements `json:"resources,omitempty"`
}

// GPUClusterStatus defines the observed state of GPUCluster
type GPUClusterStatus struct {
// +kubebuilder:validation:Enum=ignored;ready;notReady;disabled
// State indicates the status of the GPUCluster instance
State State `json:"state"`
// Namespace indicates the namespace in which the operator and operands are installed
Namespace string `json:"namespace,omitempty"`
// Conditions is a list of conditions representing the GPUCluster's current state.
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +genclient
// +genclient:nonNamespaced
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:resource:scope=Cluster,shortName={"gc"}
//+kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.state`,priority=0
//+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,priority=0

// GPUCluster is the Schema for the gpuclusters API
type GPUCluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec GPUClusterSpec `json:"spec,omitempty"`
Status GPUClusterStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// GPUClusterList contains a list of GPUCluster
type GPUClusterList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []GPUCluster `json:"items"`
}
1 change: 1 addition & 0 deletions api/nvidia/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (

func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, &NVIDIADriver{}, &NVIDIADriverList{})
scheme.AddKnownTypes(SchemeGroupVersion, &GPUCluster{}, &GPUClusterList{})
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
Loading
Loading