Skip to content

Commit 7532bdb

Browse files
authored
feat: Enable Cloud Connector ECS autoscaling based on RAM (#157)
1 parent 2c7d18f commit 7532bdb

File tree

14 files changed

+152
-5
lines changed

14 files changed

+152
-5
lines changed

examples/single-account-ecs/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ $ terraform apply
113113
| <a name="input_ecs_vpc_id"></a> [ecs\_vpc\_id](#input\_ecs\_vpc\_id) | ID of the VPC where the workload is to be deployed. If defaulted a new VPC will be created. If specified all three parameters `ecs_cluster_name`, `ecs_vpc_id` and `ecs_vpc_subnets_private_ids` are required | `string` | `"create"` | no |
114114
| <a name="input_ecs_vpc_region_azs"></a> [ecs\_vpc\_region\_azs](#input\_ecs\_vpc\_region\_azs) | List of Availability Zones for ECS VPC creation. e.g.: ["apne1-az1", "apne1-az2"]. If defaulted, two of the default 'aws\_availability\_zones' datasource will be taken | `list(string)` | `[]` | no |
115115
| <a name="input_ecs_vpc_subnets_private_ids"></a> [ecs\_vpc\_subnets\_private\_ids](#input\_ecs\_vpc\_subnets\_private\_ids) | List of VPC subnets where workload is to be deployed. If defaulted new subnets will be created within the VPC. A minimum of two subnets is suggested. If specified all three parameters `ecs_cluster_name`, `ecs_vpc_id` and `ecs_vpc_subnets_private_ids` are required. | `list(string)` | `[]` | no |
116+
| <a name="input_enable_autoscaling"></a> [enable\_autoscaling](#input\_enable\_autoscaling) | Whether to enable autoscaling or not | `bool` | `false` | no |
117+
| <a name="input_max_replicas"></a> [max\_replicas](#input\_max\_replicas) | If autoscaling is enabled, this is the maximum number of replicas to run | `number` | `10` | no |
118+
| <a name="input_min_replicas"></a> [min\_replicas](#input\_min\_replicas) | If autoscaling is enabled, this is the minimum number of replicas to run | `number` | `1` | no |
116119
| <a name="input_name"></a> [name](#input\_name) | Name to be assigned to all child resources. A suffix may be added internally when required. Use default value unless you need to install multiple instances | `string` | `"sfc"` | no |
117120
| <a name="input_tags"></a> [tags](#input\_tags) | customization of tags to be assigned to all resources. <br/>always include 'product' default tag for resource-group proper functioning.<br/>can also make use of the [provider-level `default-tags`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags) | `map(string)` | <pre>{<br> "product": "sysdig-secure-for-cloud"<br>}</pre> | no |
118121

examples/single-account-ecs/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,8 @@ module "cloud_connector" {
6666

6767
tags = var.tags
6868
depends_on = [local.cloudtrail_sns_arn, module.ssm]
69+
70+
enable_autoscaling = var.enable_autoscaling
71+
min_replicas = var.min_replicas
72+
max_replicas = var.max_replicas
6973
}

examples/single-account-ecs/variables.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,25 @@ variable "tags" {
136136
"product" = "sysdig-secure-for-cloud"
137137
}
138138
}
139+
140+
#
141+
# Autoscaling configurations
142+
#
143+
variable "enable_autoscaling" {
144+
type = bool
145+
description = "Whether to enable autoscaling or not"
146+
default = false
147+
}
148+
149+
150+
variable "min_replicas" {
151+
type = number
152+
default = 1
153+
description = "If autoscaling is enabled, this is the minimum number of replicas to run"
154+
}
155+
156+
variable "max_replicas" {
157+
type = number
158+
default = 10
159+
description = "If autoscaling is enabled, this is the maximum number of replicas to run"
160+
}

modules/services/cloud-connector-ecs/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ A task deployed on an **ECS deployment** will detect events in your infrastructu
2828

2929
| Name | Type |
3030
|------|------|
31+
| [aws_appautoscaling_policy.ecs_ram_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource |
32+
| [aws_appautoscaling_target.ecs_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target) | resource |
3133
| [aws_cloudwatch_log_group.log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
3234
| [aws_cloudwatch_log_stream.stream](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_stream) | resource |
35+
| [aws_cloudwatch_metric_alarm.ecs_ram_usage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |
3336
| [aws_ecs_service.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
3437
| [aws_ecs_task_definition.task_definition](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
3538
| [aws_iam_role.execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
@@ -76,10 +79,13 @@ A task deployed on an **ECS deployment** will detect events in your infrastructu
7679
| <a name="input_deploy_image_scanning_ecs"></a> [deploy\_image\_scanning\_ecs](#input\_deploy\_image\_scanning\_ecs) | true/false whether to deploy the image scanning on ECS running images | `bool` | `false` | no |
7780
| <a name="input_ecs_task_cpu"></a> [ecs\_task\_cpu](#input\_ecs\_task\_cpu) | Amount of CPU (in CPU units) to reserve for cloud-connector task | `string` | `"256"` | no |
7881
| <a name="input_ecs_task_memory"></a> [ecs\_task\_memory](#input\_ecs\_task\_memory) | Amount of memory (in megabytes) to reserve for cloud-connector task | `string` | `"512"` | no |
82+
| <a name="input_enable_autoscaling"></a> [enable\_autoscaling](#input\_enable\_autoscaling) | Enable autoscaling for the ECS service | `bool` | `false` | no |
7983
| <a name="input_existing_cloudtrail_config"></a> [existing\_cloudtrail\_config](#input\_existing\_cloudtrail\_config) | Optional block. If not set, a new cloudtrail, sns and sqs resources will be created<br/><br>If there's an existing cloudtrail, input mandatory attributes, and one of the 1 or 2 labeled optionals.<br><ul><br> <li>cloudtrail\_sns\_arn: Optional 1. ARN of a cloudtrail-sns topic. If specified, deployment region must match Cloudtrail S3 bucket region</li><br> <li>cloudtrail\_s3\_sns\_sqs\_arn: Optional 2. ARN of the queue that will ingest events forwarded from an existing cloudtrail\_s3\_sns</li><br> <li>cloudtrail\_s3\_sns\_sqs\_url: Optional 2. URL of the queue that will ingest events forwarded from an existing cloudtrail\_s3\_sns<br/>sqs:ReceiveMessage and sqs:DeleteMessage permissions have to be provided to the compute role</li><br></ul> | <pre>object({<br> cloudtrail_sns_arn = optional(string)<br> cloudtrail_s3_sns_sqs_arn = optional(string)<br> cloudtrail_s3_sns_sqs_url = optional(string)<br> })</pre> | <pre>{<br> "cloudtrail_s3_sns_sqs_arn": null,<br> "cloudtrail_s3_sns_sqs_url": null,<br> "cloudtrail_sns_arn": "create"<br>}</pre> | no |
8084
| <a name="input_extra_env_vars"></a> [extra\_env\_vars](#input\_extra\_env\_vars) | Extra environment variables for the Cloud Connector deployment | `map(string)` | `{}` | no |
8185
| <a name="input_image"></a> [image](#input\_image) | Image of the cloud connector to deploy | `string` | `"quay.io/sysdig/cloud-connector:latest"` | no |
8286
| <a name="input_is_organizational"></a> [is\_organizational](#input\_is\_organizational) | true/false whether `organizational_config` should be used to handle organizational setup | `bool` | `false` | no |
87+
| <a name="input_max_replicas"></a> [max\_replicas](#input\_max\_replicas) | If autoscaling is enabled, this is the maximum number of replicas to run | `number` | `10` | no |
88+
| <a name="input_min_replicas"></a> [min\_replicas](#input\_min\_replicas) | If autoscaling is enabled, this is the minimum number of replicas to run | `number` | `1` | no |
8389
| <a name="input_name"></a> [name](#input\_name) | Name to be assigned to all child resources. A suffix may be added internally when required. Use default value unless you need to install multiple instances | `string` | `"sfc-cloudconnector"` | no |
8490
| <a name="input_organizational_config"></a> [organizational\_config](#input\_organizational\_config) | organizational\_config. following attributes must be given<br><ul><br> <li>`sysdig_secure_for_cloud_role_arn` for cloud-connector assumeRole in order to read cloudtrail s3 events</li><br> <li>`connector_ecs_task_role_name` which has been granted trusted-relationship over the secure\_for\_cloud\_role</li><br> <li>`organizational_role_per_account` is the name of the organizational role deployed by AWS in each account of the organization. used for image-scanning only</li><br></ul> | <pre>object({<br> sysdig_secure_for_cloud_role_arn = string<br> organizational_role_per_account = string<br> connector_ecs_task_role_name = string<br> })</pre> | <pre>{<br> "connector_ecs_task_role_name": null,<br> "organizational_role_per_account": null,<br> "sysdig_secure_for_cloud_role_arn": null<br>}</pre> | no |
8591
| <a name="input_tags"></a> [tags](#input\_tags) | customization of tags to be assigned to all resources. <br/>always include 'product' default tag for resource-group proper functioning.<br/>can also make use of the [provider-level `default-tags`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags) | `map(string)` | <pre>{<br> "product": "sysdig-secure-for-cloud"<br>}</pre> | no |
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
resource "aws_appautoscaling_target" "ecs_target" {
2+
count = var.enable_autoscaling ? 1 : 0
3+
4+
max_capacity = var.max_replicas
5+
min_capacity = var.min_replicas
6+
resource_id = "service/${data.aws_ecs_cluster.this.cluster_name}/${aws_ecs_service.service.name}"
7+
scalable_dimension = "ecs:service:DesiredCount"
8+
service_namespace = "ecs"
9+
}
10+
11+
resource "aws_appautoscaling_policy" "ecs_ram_policy" {
12+
count = var.enable_autoscaling ? 1 : 0
13+
14+
name = "scale-cloud-connector-ram-usage"
15+
policy_type = "StepScaling"
16+
resource_id = aws_appautoscaling_target.ecs_target[0].resource_id
17+
scalable_dimension = aws_appautoscaling_target.ecs_target[0].scalable_dimension
18+
service_namespace = aws_appautoscaling_target.ecs_target[0].service_namespace
19+
20+
step_scaling_policy_configuration {
21+
adjustment_type = "ChangeInCapacity"
22+
cooldown = 30
23+
metric_aggregation_type = "Average"
24+
25+
# Scale down on Memory usage if it's below 40% usage
26+
step_adjustment {
27+
metric_interval_upper_bound = -10
28+
scaling_adjustment = -1
29+
}
30+
31+
# Do not scale if Memory usage is between 40% and 60% usage
32+
step_adjustment {
33+
metric_interval_lower_bound = -10
34+
metric_interval_upper_bound = 10
35+
scaling_adjustment = 0
36+
}
37+
38+
# Scale up on Memory usage if it's above 60% usage
39+
step_adjustment {
40+
metric_interval_lower_bound = 10
41+
scaling_adjustment = 1
42+
}
43+
44+
}
45+
}
46+
47+
resource "aws_cloudwatch_metric_alarm" "ecs_ram_usage" {
48+
count = var.enable_autoscaling ? 1 : 0
49+
50+
alarm_name = "Step-Scaling-AlarmHigh-ECS:service/${data.aws_ecs_cluster.this.cluster_name}/${aws_ecs_service.service.name}"
51+
52+
metric_name = "MemoryUtilization"
53+
namespace = "AWS/EC2"
54+
statistic = "Average"
55+
56+
period = "30"
57+
evaluation_periods = "2"
58+
threshold = "50"
59+
60+
comparison_operator = "GreaterThanOrEqualToThreshold"
61+
62+
dimensions = {
63+
Name = data.aws_ecs_cluster.this.cluster_name,
64+
ServiceName = aws_ecs_service.service.name
65+
}
66+
67+
alarm_actions = [aws_appautoscaling_policy.ecs_ram_policy[0].arn]
68+
69+
alarm_description = "This metric monitors ECS Memory Utilization of Cloud Connector"
70+
}

modules/services/cloud-connector-ecs/ecs-service.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ resource "aws_ecs_service" "service" {
1616
task_definition = aws_ecs_task_definition.task_definition.arn
1717
wait_for_steady_state = true
1818
tags = var.tags
19+
20+
lifecycle {
21+
ignore_changes = [desired_count]
22+
}
1923
}
2024

2125

modules/services/cloud-connector-ecs/variables.tf

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ variable "existing_cloudtrail_config" {
6161
}
6262

6363

64-
6564
#---------------------------------
6665
# optionals - with default
6766
#---------------------------------
@@ -148,7 +147,6 @@ variable "extra_env_vars" {
148147
}
149148

150149

151-
152150
#
153151
# scanning configuration
154152
#
@@ -172,7 +170,6 @@ variable "deploy_image_scanning_ecs" {
172170
}
173171

174172

175-
176173
#
177174
# general
178175
#
@@ -189,3 +186,24 @@ variable "tags" {
189186
"product" = "sysdig-secure-for-cloud"
190187
}
191188
}
189+
190+
#
191+
# autoscaling
192+
#
193+
variable "enable_autoscaling" {
194+
type = bool
195+
default = false
196+
description = "Enable autoscaling for the ECS service"
197+
}
198+
199+
variable "min_replicas" {
200+
type = number
201+
default = 1
202+
description = "If autoscaling is enabled, this is the minimum number of replicas to run"
203+
}
204+
205+
variable "max_replicas" {
206+
type = number
207+
default = 10
208+
description = "If autoscaling is enabled, this is the maximum number of replicas to run"
209+
}

test/fixtures/organizational-k8s/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ terraform {
33
sysdig = {
44
source = "sysdiglabs/sysdig"
55
}
6+
aws = {
7+
source = "hashicorp/aws"
8+
version = "<4.51.0"
9+
}
610
}
711
}
812

test/fixtures/organizational-single/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
terraform {
22
required_providers {
33
aws = {
4-
version = ">= 4.0.0"
4+
version = ">= 4.0.0, <4.51.0"
55
configuration_aliases = [aws.member]
66
}
77
sysdig = {

test/fixtures/organizational/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
terraform {
22
required_providers {
33
aws = {
4-
version = ">= 4.0.0"
4+
version = ">= 4.0.0, <4.51.0"
55
configuration_aliases = [aws.member]
66
}
77
sysdig = {

test/fixtures/single-account-apprunner/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ terraform {
44
source = "sysdiglabs/sysdig"
55
version = ">=0.5.33"
66
}
7+
aws = {
8+
source = "hashicorp/aws"
9+
version = "<4.51.0"
10+
}
711
}
812
}
913

test/fixtures/single-account-ecs/main.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ terraform {
44
source = "sysdiglabs/sysdig"
55
version = ">=0.5.33"
66
}
7+
aws = {
8+
source = "hashicorp/aws"
9+
version = "<4.51.0"
10+
}
711
}
812
}
913

@@ -22,4 +26,8 @@ module "cloudvision_aws_single_account_ecs" {
2226

2327
deploy_image_scanning_ecr = true
2428
deploy_image_scanning_ecs = true
29+
30+
enable_autoscaling = true
31+
min_replicas = 2
32+
max_replicas = 4
2533
}

test/fixtures/single-account-ecs/outputs.tf

Whitespace-only changes.

test/fixtures/single-account-k8s/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ terraform {
33
sysdig = {
44
source = "sysdiglabs/sysdig"
55
}
6+
aws = {
7+
source = "hashicorp/aws"
8+
version = "<4.51.0"
9+
}
610
}
711
}
812

0 commit comments

Comments
 (0)