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
import (
"encoding/json"
"fmt"
applicationautoscaling2 "github.com/aws/aws-sdk-go/service/applicationautoscaling"
@ -26,13 +27,37 @@ import (
"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 {
return
return nil
}
v, ok := service.Deploy.Extensions[extensionAutoScaling]
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))
@ -66,8 +91,8 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
target := fmt.Sprintf("%sScalableTarget", normalizeResourceName(service.Name))
template.Resources[target] = &applicationautoscaling.ScalableTarget{
MaxCapacity: 10,
MinCapacity: 0,
MaxCapacity: config.Max,
MinCapacity: config.Min,
ResourceId: resourceID,
RoleARN: cloudformation.GetAtt(role, "Arn"),
ScalableDimension: applicationautoscaling2.ScalableDimensionEcsServiceDesiredCount,
@ -75,6 +100,15 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
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))
template.Resources[policy] = &applicationautoscaling.ScalingPolicy{
PolicyType: "TargetTrackingScaling",
@ -83,11 +117,12 @@ func (b *ecsAPIService) createAutoscalingPolicy(project *types.Project, resource
StepScalingPolicyConfiguration: nil,
TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.ScalingPolicy_TargetTrackingScalingPolicyConfiguration{
PredefinedMetricSpecification: &applicationautoscaling.ScalingPolicy_PredefinedMetricSpecification{
PredefinedMetricType: applicationautoscaling2.MetricTypeEcsserviceAverageCpuutilization,
PredefinedMetricType: metric,
},
ScaleOutCooldown: 60,
ScaleInCooldown: 60,
TargetValue: float64(v.(int)),
TargetValue: float64(targetPercent),
},
}
return nil
}

View File

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

View File

@ -85,7 +85,10 @@ func (b *ecsAPIService) convert(ctx context.Context, project *types.Project) (*c
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)