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
3 changes: 3 additions & 0 deletions .changes/unreleased/added-20261020-223519.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Added
body: |-
Add horizontal autoscaling configuration for admission service
30 changes: 30 additions & 0 deletions config/crd/kai.scheduler_configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,36 @@ spec:
admission:
description: Admission holds KAI admission webhooks
properties:
autoscaling:
description: Autoscaling configures horizontal autoscaling for
the admission service
properties:
enabled:
description: Enabled enables horizontal autoscaling for the
admission service.
type: boolean
maxReplicas:
description: MaxReplicas specifies the maximum number of admission
replicas.
format: int32
minimum: 1
type: integer
targetCPUUtilizationPercentage:
description: |-
TargetCPUUtilizationPercentage specifies the target average CPU utilization
across admission pods.
format: int32
maximum: 100
minimum: 1
type: integer
targetInFlightRequests:
description: |-
TargetInFlightRequests specifies the target average number of in-flight
webhook requests per admission pod.
format: int32
minimum: 1
type: integer
type: object
blockNvidiaVisibleDevices:
description: |-
BlockNvidiaVisibleDevices prevents pods from overriding the NVIDIA_VISIBLE_DEVICES
Expand Down
37 changes: 37 additions & 0 deletions kai/v1/admission/admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type Admission struct {
// +kubebuilder:validation:Optional
Replicas *int32 `json:"replicas,omitempty"`

// Autoscaling configures horizontal autoscaling for the admission service
// +kubebuilder:validation:Optional
Autoscaling *Autoscaling `json:"autoscaling,omitempty"`

// GPUSharing enables GPU sharing functionality for the admission service
// +kubebuilder:validation:Optional
GPUSharing *bool `json:"gpuSharing,omitempty"`
Expand Down Expand Up @@ -80,6 +84,35 @@ type Admission struct {
InPlacePodResize *InPlacePodResize `json:"inPlacePodResize,omitempty"`
}

// Autoscaling defines horizontal autoscaling configuration for the admission service.
type Autoscaling struct {
// Enabled enables horizontal autoscaling for the admission service.
// +kubebuilder:validation:Optional
Enabled *bool `json:"enabled,omitempty"`

// MaxReplicas specifies the maximum number of admission replicas.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
MaxReplicas *int32 `json:"maxReplicas,omitempty"`

// TargetInFlightRequests specifies the target average number of in-flight
// webhook requests per admission pod.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
TargetInFlightRequests *int32 `json:"targetInFlightRequests,omitempty"`

// TargetCPUUtilizationPercentage specifies the target average CPU utilization
// across admission pods.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=100
TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage,omitempty"`
}

func (a *Autoscaling) SetDefaultsWhereNeeded() {
a.Enabled = common.SetDefault(a.Enabled, ptr.To(false))
}

// InPlacePodResize configures KEP-1287 in-place pod resize admission behaviour.
type InPlacePodResize struct {
// ValidateQuota enables best-effort hierarchical queue quota checks on
Expand Down Expand Up @@ -110,6 +143,10 @@ func (b *Admission) SetDefaultsWhereNeeded(replicaCount *int32, globalVPA *commo
b.Webhook.SetDefaultsWhereNeeded()

b.Replicas = common.SetDefault(b.Replicas, ptr.To(ptr.Deref(replicaCount, 1)))
if b.Autoscaling != nil {
b.Autoscaling.SetDefaultsWhereNeeded()
}

b.GPUSharing = common.SetDefault(b.GPUSharing, ptr.To(gpuSharingEnabledForMode(gpuSharingMode)))
b.QueueLabelSelector = common.SetDefault(b.QueueLabelSelector, ptr.To(false))
b.BlockNvidiaVisibleDevices = common.SetDefault(b.BlockNvidiaVisibleDevices, ptr.To(false))
Expand Down
38 changes: 38 additions & 0 deletions kai/v1/admission/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,42 @@ var _ = Describe("Admission", func() {
Admission.SetDefaultsWhereNeeded(nil, nil, common.GpuSharingModeHamiCore)
Expect(*Admission.GPUSharing).To(BeFalse())
})
It("does not configure autoscaling by default", func(ctx context.Context) {
admission := &Admission{}

admission.SetDefaultsWhereNeeded(nil, nil, common.GpuSharingModeNonMemoryEnforced)

Expect(admission.Autoscaling).To(BeNil())
})

It("sets autoscaling defaults when configured", func(ctx context.Context) {
admission := &Admission{
Autoscaling: &Autoscaling{},
}

admission.SetDefaultsWhereNeeded(nil, nil, common.GpuSharingModeNonMemoryEnforced)

Expect(*admission.Autoscaling.Enabled).To(BeFalse())
Expect(admission.Autoscaling.MaxReplicas).To(BeNil())
Expect(admission.Autoscaling.TargetInFlightRequests).To(BeNil())
Expect(admission.Autoscaling.TargetCPUUtilizationPercentage).To(BeNil())
})

It("preserves explicit autoscaling configuration", func(ctx context.Context) {
admission := &Admission{
Autoscaling: &Autoscaling{
Enabled: ptr.To(true),
MaxReplicas: ptr.To(int32(5)),
TargetInFlightRequests: ptr.To(int32(20)),
TargetCPUUtilizationPercentage: ptr.To(int32(80)),
},
}

admission.SetDefaultsWhereNeeded(nil, nil, common.GpuSharingModeNonMemoryEnforced)

Expect(*admission.Autoscaling.Enabled).To(BeTrue())
Expect(*admission.Autoscaling.MaxReplicas).To(Equal(int32(5)))
Expect(*admission.Autoscaling.TargetInFlightRequests).To(Equal(int32(20)))
Expect(*admission.Autoscaling.TargetCPUUtilizationPercentage).To(Equal(int32(80)))
})
})
40 changes: 40 additions & 0 deletions kai/v1/admission/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.