diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c442d62fd..df115e6531a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Here is an overview of all new **experimental** features: ### Improvements - **General**: Add OPENTELEMETRY flag in e2e test YAML ([#5375](https://github.com/kedacore/keda/issues/5375)) +- **General**: Add startReplicaCount parameter to ScaledObject for scaling from 0 to N replicas ### Fixes diff --git a/apis/keda/v1alpha1/scaledobject_types.go b/apis/keda/v1alpha1/scaledobject_types.go index 0e8ddf614fe..67cea9b225d 100644 --- a/apis/keda/v1alpha1/scaledobject_types.go +++ b/apis/keda/v1alpha1/scaledobject_types.go @@ -33,6 +33,7 @@ import ( // +kubebuilder:printcolumn:name="ScaleTargetName",type="string",JSONPath=".spec.scaleTargetRef.name" // +kubebuilder:printcolumn:name="Min",type="integer",JSONPath=".spec.minReplicaCount" // +kubebuilder:printcolumn:name="Max",type="integer",JSONPath=".spec.maxReplicaCount" +// +kubebuilder:printcolumn:name="Start",type="integer",JSONPath=".spec.startReplicaCount" // +kubebuilder:printcolumn:name="Triggers",type="string",JSONPath=".spec.triggers[*].type" // +kubebuilder:printcolumn:name="Authentication",type="string",JSONPath=".spec.triggers[*].authenticationRef.name" // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status" @@ -95,6 +96,8 @@ type ScaledObjectSpec struct { // +optional MaxReplicaCount *int32 `json:"maxReplicaCount,omitempty"` // +optional + StartReplicaCount *int32 `json:"startReplicaCount,omitempty"` + // +optional Advanced *AdvancedConfig `json:"advanced,omitempty"` Triggers []ScaleTriggers `json:"triggers"` @@ -256,6 +259,10 @@ func CheckReplicaCountBoundsAreValid(scaledObject *ScaledObject) error { } max := scaledObject.GetHPAMaxReplicas() + if scaledObject.Spec.StartReplicaCount != nil && (*scaledObject.Spec.StartReplicaCount > max || *scaledObject.Spec.StartReplicaCount < min) { + return fmt.Errorf("StartReplicaCount=%d must be less than or equal to MaxReplicaCount=%d and greater than or equal to MinReplicaCount=%d", *scaledObject.Spec.StartReplicaCount, max, min) + } + if min > max { return fmt.Errorf("MinReplicaCount=%d must be less than MaxReplicaCount=%d", min, max) } diff --git a/config/crd/bases/keda.sh_scaledobjects.yaml b/config/crd/bases/keda.sh_scaledobjects.yaml index f103979c8b0..9e584bf7eb7 100644 --- a/config/crd/bases/keda.sh_scaledobjects.yaml +++ b/config/crd/bases/keda.sh_scaledobjects.yaml @@ -29,6 +29,9 @@ spec: - jsonPath: .spec.maxReplicaCount name: Max type: integer + - jsonPath: .spec.startReplicaCount + name: Start + type: integer - jsonPath: .spec.triggers[*].type name: Triggers type: string @@ -244,6 +247,9 @@ spec: minReplicaCount: format: int32 type: integer + startReplicaCount: + format: int32 + type: integer pollingInterval: format: int32 type: integer diff --git a/pkg/scaling/executor/scale_scaledobjects.go b/pkg/scaling/executor/scale_scaledobjects.go index 908237a275c..6697fe664cf 100644 --- a/pkg/scaling/executor/scale_scaledobjects.go +++ b/pkg/scaling/executor/scale_scaledobjects.go @@ -297,7 +297,9 @@ func (e *scaleExecutor) scaleToZeroOrIdle(ctx context.Context, logger logr.Logge func (e *scaleExecutor) scaleFromZeroOrIdle(ctx context.Context, logger logr.Logger, scaledObject *kedav1alpha1.ScaledObject, scale *autoscalingv1.Scale) { var replicas int32 - if scaledObject.Spec.MinReplicaCount != nil && *scaledObject.Spec.MinReplicaCount > 0 { + if scaledObject.Spec.StartReplicaCount != nil && scaledObject.Spec.MinReplicaCount != nil && *scaledObject.Spec.StartReplicaCount > *scaledObject.Spec.MinReplicaCount { + replicas = *scaledObject.Spec.StartReplicaCount + } else if scaledObject.Spec.MinReplicaCount != nil && *scaledObject.Spec.MinReplicaCount > 0 { replicas = *scaledObject.Spec.MinReplicaCount } else { replicas = 1