From 205e3e607d6128a536056814c2a3c2188abed000 Mon Sep 17 00:00:00 2001 From: Piotr Szczesniak Date: Mon, 29 Feb 2016 12:02:54 +0100 Subject: [PATCH] Added default cpu target for HPA --- api/swagger-spec/autoscaling_v1.json | 2 +- pkg/apis/autoscaling/v1/types.go | 1 + .../v1/types_swagger_doc_generated.go | 2 +- pkg/controller/podautoscaler/horizontal.go | 17 ++++++------ .../podautoscaler/horizontal_test.go | 26 +++++++++++++++++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/api/swagger-spec/autoscaling_v1.json b/api/swagger-spec/autoscaling_v1.json index ddb9e5064c7..fea26906d3e 100644 --- a/api/swagger-spec/autoscaling_v1.json +++ b/api/swagger-spec/autoscaling_v1.json @@ -1001,7 +1001,7 @@ "targetCPUUtilizationPercentage": { "type": "integer", "format": "int32", - "description": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods;" + "description": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods; if not specified the default autoscaling policy will be used." } } }, diff --git a/pkg/apis/autoscaling/v1/types.go b/pkg/apis/autoscaling/v1/types.go index ff53a5ddc5a..58d886641ca 100644 --- a/pkg/apis/autoscaling/v1/types.go +++ b/pkg/apis/autoscaling/v1/types.go @@ -41,6 +41,7 @@ type HorizontalPodAutoscalerSpec struct { // upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas. MaxReplicas int32 `json:"maxReplicas"` // target average CPU utilization (represented as a percentage of requested CPU) over all the pods; + // if not specified the default autoscaling policy will be used. TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage,omitempty"` } diff --git a/pkg/apis/autoscaling/v1/types_swagger_doc_generated.go b/pkg/apis/autoscaling/v1/types_swagger_doc_generated.go index 9fb4becb536..56ed2baccc6 100644 --- a/pkg/apis/autoscaling/v1/types_swagger_doc_generated.go +++ b/pkg/apis/autoscaling/v1/types_swagger_doc_generated.go @@ -64,7 +64,7 @@ var map_HorizontalPodAutoscalerSpec = map[string]string{ "scaleTargetRef": "reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption and will set the desired number of pods by using its Scale subresource.", "minReplicas": "lower limit for the number of pods that can be set by the autoscaler, default 1.", "maxReplicas": "upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.", - "targetCPUUtilizationPercentage": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods;", + "targetCPUUtilizationPercentage": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods; if not specified the default autoscaling policy will be used.", } func (HorizontalPodAutoscalerSpec) SwaggerDoc() map[string]string { diff --git a/pkg/controller/podautoscaler/horizontal.go b/pkg/controller/podautoscaler/horizontal.go index 7b0f9248d65..815477488e9 100644 --- a/pkg/controller/podautoscaler/horizontal.go +++ b/pkg/controller/podautoscaler/horizontal.go @@ -39,6 +39,8 @@ const ( // TODO: make it a flag or HPA spec element. tolerance = 0.1 + defaultTargetCPUUtilizationPercentage = 80 + HpaCustomMetricsTargetAnnotationName = "alpha/target.custom-metrics.podautoscaler.kubernetes.io" HpaCustomMetricsStatusAnnotationName = "alpha/status.custom-metrics.podautoscaler.kubernetes.io" ) @@ -76,11 +78,9 @@ func (a *HorizontalController) Run(syncPeriod time.Duration) { } func (a *HorizontalController) computeReplicasForCPUUtilization(hpa extensions.HorizontalPodAutoscaler, scale *extensions.Scale) (int, *int, time.Time, error) { - if hpa.Spec.CPUUtilization == nil { - // If CPUTarget is not specified than we should return some default values. - // Since we always take maximum number of replicas from all policies it is safe - // to just return 0. - return 0, nil, time.Time{}, nil + targetUtilization := defaultTargetCPUUtilizationPercentage + if hpa.Spec.CPUUtilization != nil { + targetUtilization = hpa.Spec.CPUUtilization.TargetPercentage } currentReplicas := scale.Status.Replicas currentUtilization, timestamp, err := a.metricsClient.GetCPUUtilization(hpa.Namespace, scale.Status.Selector) @@ -91,7 +91,7 @@ func (a *HorizontalController) computeReplicasForCPUUtilization(hpa extensions.H return 0, nil, time.Time{}, fmt.Errorf("failed to get cpu utilization: %v", err) } - usageRatio := float64(*currentUtilization) / float64(hpa.Spec.CPUUtilization.TargetPercentage) + usageRatio := float64(*currentUtilization) / float64(targetUtilization) if math.Abs(1.0-usageRatio) > tolerance { return int(math.Ceil(usageRatio * float64(currentReplicas))), currentUtilization, timestamp, nil } else { @@ -192,8 +192,9 @@ func (a *HorizontalController) reconcileAutoscaler(hpa extensions.HorizontalPodA desiredReplicas = 1 } else { // All basic scenarios covered, the state should be sane, lets use metrics. + cmAnnotation, cmAnnotationFound := hpa.Annotations[HpaCustomMetricsTargetAnnotationName] - if hpa.Spec.CPUUtilization != nil { + if hpa.Spec.CPUUtilization != nil || !cmAnnotationFound { cpuDesiredReplicas, cpuCurrentUtilization, cpuTimestamp, err = a.computeReplicasForCPUUtilization(hpa, scale) if err != nil { a.updateCurrentReplicasInStatus(hpa, currentReplicas) @@ -202,7 +203,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpa extensions.HorizontalPodA } } - if cmAnnotation, cmAnnotationFound := hpa.Annotations[HpaCustomMetricsTargetAnnotationName]; cmAnnotationFound { + if cmAnnotationFound { cmDesiredReplicas, cmStatus, cmTimestamp, err = a.computeReplicasForCustomMetrics(hpa, scale, cmAnnotation) if err != nil { a.updateCurrentReplicasInStatus(hpa, currentReplicas) diff --git a/pkg/controller/podautoscaler/horizontal_test.go b/pkg/controller/podautoscaler/horizontal_test.go index cd72a3689e7..ddbd453311e 100644 --- a/pkg/controller/podautoscaler/horizontal_test.go +++ b/pkg/controller/podautoscaler/horizontal_test.go @@ -257,6 +257,19 @@ func (tc *testCase) runTest(t *testing.T) { tc.verifyResults(t) } +func TestDefaultScaleUp(t *testing.T) { + tc := testCase{ + minReplicas: 2, + maxReplicas: 6, + initialReplicas: 4, + desiredReplicas: 5, + verifyCPUCurrent: true, + reportedLevels: []uint64{900, 950, 950, 1000}, + reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + } + tc.runTest(t) +} + func TestScaleUp(t *testing.T) { tc := testCase{ minReplicas: 2, @@ -290,6 +303,19 @@ func TestScaleUpCM(t *testing.T) { tc.runTest(t) } +func TestDefaultScaleDown(t *testing.T) { + tc := testCase{ + minReplicas: 2, + maxReplicas: 6, + initialReplicas: 5, + desiredReplicas: 4, + verifyCPUCurrent: true, + reportedLevels: []uint64{400, 500, 600, 700, 800}, + reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + } + tc.runTest(t) +} + func TestScaleDown(t *testing.T) { tc := testCase{ minReplicas: 2,