Merge pull request #817 from docker/scalescale

Configure autoscaling parameters
This commit is contained in:
Nicolas De loof 2020-10-21 10:56:28 +02:00 committed by GitHub
commit 34a7466571
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 13 deletions

View File

@ -17,6 +17,7 @@
package ecs package ecs
import ( import (
"encoding/json"
"fmt" "fmt"
applicationautoscaling2 "github.com/aws/aws-sdk-go/service/applicationautoscaling" applicationautoscaling2 "github.com/aws/aws-sdk-go/service/applicationautoscaling"
@ -26,13 +27,37 @@ import (
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
) )
func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resources awsResources, template *cloudformation.Template, service types.ServiceConfig) { type autoscalingConfig struct {
Memory int `json:"memory,omitempty"`
CPU int `json:"cpu,omitempty"`
Min int `json:"min,omitempty"`
Max int `json:"max,omitempty"`
}
func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resources awsResources, template *cloudformation.Template, service types.ServiceConfig) error {
if service.Deploy == nil { if service.Deploy == nil {
return return nil
} }
v, ok := service.Deploy.Extensions[extensionAutoScaling] v, ok := service.Deploy.Extensions[extensionAutoScaling]
if !ok { if !ok {
return return nil
}
marshalled, err := json.Marshal(v)
if err != nil {
return err
}
var config autoscalingConfig
err = json.Unmarshal(marshalled, &config)
if err != nil {
return err
}
if config.Memory != 0 && config.CPU != 0 {
return fmt.Errorf("%s can't be set with both cpu and memory targets", extensionAutoScaling)
}
if config.Max == 0 {
return fmt.Errorf("%s MUST define max replicas", extensionAutoScaling)
} }
role := fmt.Sprintf("%sAutoScalingRole", normalizeResourceName(service.Name)) role := fmt.Sprintf("%sAutoScalingRole", normalizeResourceName(service.Name))
@ -66,8 +91,8 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
target := fmt.Sprintf("%sScalableTarget", normalizeResourceName(service.Name)) target := fmt.Sprintf("%sScalableTarget", normalizeResourceName(service.Name))
template.Resources[target] = &applicationautoscaling.ScalableTarget{ template.Resources[target] = &applicationautoscaling.ScalableTarget{
MaxCapacity: 10, MaxCapacity: config.Max,
MinCapacity: 0, MinCapacity: config.Min,
ResourceId: resourceID, ResourceId: resourceID,
RoleARN: cloudformation.GetAtt(role, "Arn"), RoleARN: cloudformation.GetAtt(role, "Arn"),
ScalableDimension: applicationautoscaling2.ScalableDimensionEcsServiceDesiredCount, ScalableDimension: applicationautoscaling2.ScalableDimensionEcsServiceDesiredCount,
@ -75,6 +100,15 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
AWSCloudFormationDependsOn: []string{serviceResourceName(service.Name)}, AWSCloudFormationDependsOn: []string{serviceResourceName(service.Name)},
} }
var (
metric = applicationautoscaling2.MetricTypeEcsserviceAverageCpuutilization
targetPercent = config.CPU
)
if config.Memory != 0 {
metric = applicationautoscaling2.MetricTypeEcsserviceAverageMemoryUtilization
targetPercent = config.Memory
}
policy := fmt.Sprintf("%sScalingPolicy", normalizeResourceName(service.Name)) policy := fmt.Sprintf("%sScalingPolicy", normalizeResourceName(service.Name))
template.Resources[policy] = &applicationautoscaling.ScalingPolicy{ template.Resources[policy] = &applicationautoscaling.ScalingPolicy{
PolicyType: "TargetTrackingScaling", PolicyType: "TargetTrackingScaling",
@ -83,11 +117,12 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
StepScalingPolicyConfiguration: nil, StepScalingPolicyConfiguration: nil,
TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.ScalingPolicy_TargetTrackingScalingPolicyConfiguration{ TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.ScalingPolicy_TargetTrackingScalingPolicyConfiguration{
PredefinedMetricSpecification: &applicationautoscaling.ScalingPolicy_PredefinedMetricSpecification{ PredefinedMetricSpecification: &applicationautoscaling.ScalingPolicy_PredefinedMetricSpecification{
PredefinedMetricType: applicationautoscaling2.MetricTypeEcsserviceAverageCpuutilization, PredefinedMetricType: metric,
}, },
ScaleOutCooldown: 60, ScaleOutCooldown: 60,
ScaleInCooldown: 60, ScaleInCooldown: 60,
TargetValue: float64(v.(int)), TargetValue: float64(targetPercent),
}, },
} }
return nil
} }

View File

@ -29,13 +29,15 @@ services:
foo: foo:
image: hello_world image: hello_world
deploy: deploy:
x-aws-autoscaling: 75 x-aws-autoscaling:
cpu: 75
max: 10
`, useDefaultVPC) `, useDefaultVPC)
target := template.Resources["FooScalableTarget"].(*autoscaling.ScalableTarget) target := template.Resources["FooScalableTarget"].(*autoscaling.ScalableTarget)
assert.Check(t, target != nil) assert.Check(t, target != nil)
assert.Check(t, target.MaxCapacity == 10) //nolint:staticcheck
policy := template.Resources["FooScalingPolicy"].(*autoscaling.ScalingPolicy) policy := template.Resources["FooScalingPolicy"].(*autoscaling.ScalingPolicy)
if policy == nil || policy.TargetTrackingScalingPolicyConfiguration == nil { assert.Check(t, policy != nil)
t.Fail() assert.Check(t, policy.TargetTrackingScalingPolicyConfiguration.TargetValue == float64(75)) //nolint:staticcheck
}
assert.Check(t, policy.TargetTrackingScalingPolicyConfiguration.TargetValue == float64(75))
} }

View File

@ -85,7 +85,10 @@ func (b *ecsAPIService) convert(ctx context.Context, project *types.Project) (*c
return nil, err return nil, err
} }
b.createAutoscalingPolicy(project, resources, template, service) err = b.createAutoscalingPolicy(project, resources, template, service)
if err != nil {
return nil, err
}
} }
err = b.createCapacityProvider(ctx, project, template, resources) err = b.createCapacityProvider(ctx, project, template, resources)