diff --git a/docs/content/en/docs-dev/user-guide/configuration-reference.md b/docs/content/en/docs-dev/user-guide/configuration-reference.md index 8be1175265..a9a8e22b05 100644 --- a/docs/content/en/docs-dev/user-guide/configuration-reference.md +++ b/docs/content/en/docs-dev/user-guide/configuration-reference.md @@ -516,6 +516,8 @@ One of `yamlField` or `regex` is required. There are some restrictions in configuring a service definition file. +- As long as `desiredCount` is 0 or not set, `desiredCount` of your service will NOT be updated in deployments. + - If `desiredCount` is 0 or not set for a new service, the service's `desiredCount` will be 0. - `capacityProviderStrategy` is not supported. - `clientToken` is not supported. - `deploymentController` is required and must be `EXTERNAL`. diff --git a/docs/content/en/docs-dev/user-guide/managing-application/defining-app-configuration/ecs.md b/docs/content/en/docs-dev/user-guide/managing-application/defining-app-configuration/ecs.md index fba274c727..bf6c6001a2 100644 --- a/docs/content/en/docs-dev/user-guide/managing-application/defining-app-configuration/ecs.md +++ b/docs/content/en/docs-dev/user-guide/managing-application/defining-app-configuration/ecs.md @@ -155,6 +155,9 @@ spec: - That means you need to link target groups to your listener rules before deployments. - For more information and diagrams, see [Issue#4733 [ECS] Modify ELB listener rules other than defaults without adding config](https://github.com/pipe-cd/pipecd/pull/4733). - When you use [Service Connect](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect.html), you cannot use Canary or Blue/Green deployment yet because Service Connect does not support the external deployment yet. +- When you use AutoScaling for a service, you can disable reconciling `desiredCount` by following steps. + 1. Create a service without defining `desiredCount` in the service definition file. See [Restrictions of Service Definition](../../../configuration-reference/#restrictions-of-service-definition). + 2. Configure AutoScaling by yourself. ## Reference diff --git a/pkg/app/piped/executor/ecs/ecs.go b/pkg/app/piped/executor/ecs/ecs.go index 04a0567758..caf360d95d 100644 --- a/pkg/app/piped/executor/ecs/ecs.go +++ b/pkg/app/piped/executor/ecs/ecs.go @@ -278,8 +278,7 @@ func sync(ctx context.Context, in *executor.Input, platformProviderName string, cnt := service.DesiredCount // Scale down the service tasks by set it to 0 in.LogPersister.Infof("Scale down ECS desired tasks count to 0") - service.DesiredCount = 0 - if _, err = client.UpdateService(ctx, *service); err != nil { + if err = client.PruneServiceTasks(ctx, *service); err != nil { in.LogPersister.Errorf("Failed to stop service tasks: %v", err) return false } diff --git a/pkg/app/piped/platformprovider/ecs/client.go b/pkg/app/piped/platformprovider/ecs/client.go index 51eba233cc..178dca1f4b 100644 --- a/pkg/app/piped/platformprovider/ecs/client.go +++ b/pkg/app/piped/platformprovider/ecs/client.go @@ -120,16 +120,36 @@ func (c *client) CreateService(ctx context.Context, service types.Service) (*typ return output.Service, nil } +func (c *client) PruneServiceTasks(ctx context.Context, service types.Service) error { + input := &ecs.UpdateServiceInput{ + Cluster: service.ClusterArn, + Service: service.ServiceName, + DesiredCount: aws.Int32(0), + } + + _, err := c.ecsClient.UpdateService(ctx, input) + if err != nil { + return fmt.Errorf("failed to update ECS service %s: %w", *service.ServiceName, err) + } + + return nil +} + func (c *client) UpdateService(ctx context.Context, service types.Service) (*types.Service, error) { input := &ecs.UpdateServiceInput{ Cluster: service.ClusterArn, Service: service.ServiceName, - DesiredCount: aws.Int32(service.DesiredCount), EnableExecuteCommand: aws.Bool(service.EnableExecuteCommand), PlacementStrategy: service.PlacementStrategy, // TODO: Support update other properties of service. // PlacementConstraints: service.PlacementConstraints, } + + // If desiredCount is 0 or not set, keep current desiredCount because a user might use AutoScaling. + if service.DesiredCount != 0 { + input.DesiredCount = aws.Int32(service.DesiredCount) + } + output, err := c.ecsClient.UpdateService(ctx, input) if err != nil { return nil, fmt.Errorf("failed to update ECS service %s: %w", *service.ServiceName, err) diff --git a/pkg/app/piped/platformprovider/ecs/ecs.go b/pkg/app/piped/platformprovider/ecs/ecs.go index 6814b8f6ac..927d716b0e 100644 --- a/pkg/app/piped/platformprovider/ecs/ecs.go +++ b/pkg/app/piped/platformprovider/ecs/ecs.go @@ -45,6 +45,7 @@ type ECS interface { ServiceExists(ctx context.Context, clusterName string, servicesName string) (bool, error) CreateService(ctx context.Context, service types.Service) (*types.Service, error) UpdateService(ctx context.Context, service types.Service) (*types.Service, error) + PruneServiceTasks(ctx context.Context, service types.Service) error WaitServiceStable(ctx context.Context, service types.Service) error RegisterTaskDefinition(ctx context.Context, taskDefinition types.TaskDefinition) (*types.TaskDefinition, error) RunTask(ctx context.Context, taskDefinition types.TaskDefinition, clusterArn string, launchType string, awsVpcConfiguration *config.ECSVpcConfiguration, tags []types.Tag) error