Skip to content

Commit e298362

Browse files
feat: adding the capacity provider code and examples + several fixes (#44)
1 parent 9926aab commit e298362

File tree

10 files changed

+162
-14
lines changed

10 files changed

+162
-14
lines changed

CHANGELOG.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- fix: CKV_AWS_152 Ensure that Load Balancer (Network/Gateway) has cross-zone load balancing enabled
1515
- fix: CKV2_AWS_20 Ensure that ALB redirects HTTP requests into HTTPS ones
1616
- fix: CKV_AWS_261 Ensure HTTP HTTPS Target group defines Healthcheck
17-
- fix: CKV_TF_2 Ensure Terraform module sources use a tag with a version number
18-
- feat: showcase load balancer protection using WAF
19-
- feat: more than one security group for ecs service
2017
- feat: Add EC2 usage example
2118
- feat: Possibly use lb module for load-balancer resource
22-
- feat: Review ecs-service arguments, add and test those missing.
2319
- feat: Use load-balancer module in example
2420
- feat: Add more options for module cloudwatch log group
2521
- feat: Exclusively use acm certificate (not self_signed_cert) for complete example
2622
- feat: consolidate ecs cluster module and ecs service module into one
27-
- feat: Add missing aws_ecs_task_definition arguments and showcase them in examples
2823
- feat: expand volume block of the task definition as it has more configuration
2924
- feat: Add example for service security group using a security group id for `service_ingress_sg`
3025

26+
## [1.13.0] - 2025-07-03
27+
### Changes
28+
- fix: deprecated data.aws_region.current.name attribute by upgrading cluster module to v3.0.0
29+
- fix: VPC data source error by adding state filter to ensure only available VPCs are selected
30+
- fix: resource naming conflicts by adding random suffix to prevent conflicts with existing resources
31+
- fix: multiple EC2 VPCs matched error in complete example data sources
32+
- fix: deprecated data.aws_region.current.name replaced with data.aws_region.current.id in examples
33+
- feat: add capacity provider strategy support for ECS services with FARGATE and FARGATE_SPOT options
34+
- feat: add capacity_provider_strategy variable to allow mixed capacity provider deployments
35+
- feat: add fargate spot service example with capacity provider strategy configuration
36+
- feat: add fargate spot container definitions with cost optimization environment variables
37+
- feat: add random resource generation for unique naming in complete example
38+
3139
## [1.12.2] - 2024-06-10
3240
### Changes
3341
- docs: Improve variables text and change the domain name of the private acm

examples/complete/data.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ data "aws_vpc" "supporting" {
121121
name = "tag:Name"
122122
values = [var.supporting_resources_name]
123123
}
124+
125+
filter {
126+
name = "state"
127+
values = ["available"]
128+
}
124129
}
125130

126131
data "aws_subnets" "public" {

examples/complete/locals.tf

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ locals {
99
private_subnets = local.private_subnet_id
1010
vpc_id = data.aws_vpc.supporting.id
1111
cluster = data.aws_ecs_cluster.ecs.arn
12-
region = data.aws_region.current.name
12+
region = data.aws_region.current.id
1313
partition = data.aws_partition.current.partition
1414
dns_suffix = data.aws_partition.current.dns_suffix
15-
bucket = "${var.name}-access-logs-bucket-boldlink"
16-
tags = merge({ "Name" = var.name }, var.tags)
15+
bucket = "${var.name}-access-logs-bucket-${random_id.bucket_suffix.hex}"
16+
tags = merge({ "Name" = "${var.name}-${random_string.suffix.result}" }, var.tags)
1717
account_id = data.aws_caller_identity.current.account_id
1818
elb_service_account_id = data.aws_elb_service_account.main.id
1919
alb_container_definitions = jsonencode(
@@ -66,6 +66,42 @@ locals {
6666
}
6767
]
6868
)
69+
fargate_spot_container_definitions = jsonencode(
70+
[
71+
{
72+
name = var.name
73+
image = var.image
74+
cpu = var.cpu
75+
memory = var.memory
76+
essential = var.essential
77+
portMappings = [
78+
{
79+
containerPort = var.containerport
80+
hostPort = var.hostport
81+
}
82+
]
83+
logConfiguration = {
84+
logDriver = "awslogs",
85+
options = {
86+
awslogs-group = "/aws/ecs-service/${var.name}-fargate-spot-service",
87+
awslogs-region = local.region,
88+
awslogs-stream-prefix = "task"
89+
}
90+
}
91+
environment = [
92+
{
93+
name = "DEPLOYMENT_TYPE"
94+
value = "FARGATE_SPOT"
95+
},
96+
{
97+
name = "COST_OPTIMIZATION"
98+
value = "enabled"
99+
}
100+
]
101+
}
102+
]
103+
)
104+
vpc_cidr = data.aws_vpc.supporting.cidr_block
69105
task_execution_role_policy_doc = jsonencode(
70106
{
71107
Version = "2012-10-17",

examples/complete/main.tf

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
resource "random_id" "bucket_suffix" {
2+
byte_length = 4
3+
}
4+
5+
resource "random_string" "suffix" {
6+
length = 4
7+
special = false
8+
upper = false
9+
}
10+
111
module "access_logs_bucket" {
212
source = "boldlink/s3/aws"
313
version = "2.3.1"
@@ -194,3 +204,64 @@ module "ecs_service_nlb" {
194204
lb_ingress_rules = var.nlb_ingress_rules
195205
depends_on = [module.access_logs_bucket]
196206
}
207+
208+
module "ecs_service_fargate_spot" {
209+
#checkov:skip=CKV_AWS_290: "Ensure IAM policies does not allow write access without constraints"
210+
#checkov:skip=CKV_AWS_355: "Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions"
211+
source = "../../"
212+
requires_compatibilities = var.requires_compatibilities
213+
network_mode = var.network_mode
214+
name = "${var.name}-fargate-spot-service"
215+
family = "${var.name}-fargate-spot-task-definition"
216+
enable_execute_command = var.enable_execute_command
217+
218+
# Use capacity provider strategy instead of launch_type for FARGATE_SPOT
219+
capacity_provider_strategy = [
220+
{
221+
capacity_provider = "FARGATE_SPOT"
222+
weight = 4
223+
base = 0
224+
},
225+
{
226+
capacity_provider = "FARGATE"
227+
weight = 1
228+
base = 1
229+
}
230+
]
231+
232+
network_configuration = {
233+
subnets = local.private_subnets
234+
assign_public_ip = true
235+
}
236+
237+
cluster = local.cluster
238+
vpc_id = local.vpc_id
239+
task_assume_role_policy = data.aws_iam_policy_document.ecs_assume_role_policy.json
240+
task_role_policy = data.aws_iam_policy_document.task_role_policy_doc.json
241+
task_execution_assume_role_policy = data.aws_iam_policy_document.ecs_assume_role_policy.json
242+
task_execution_role_policy = local.task_execution_role_policy_doc
243+
container_definitions = local.fargate_spot_container_definitions
244+
kms_key_id = data.aws_kms_alias.supporting_kms.target_key_arn
245+
force_new_deployment = var.force_new_deployment
246+
desired_count = 3
247+
tasks_minimum_healthy_percent = 50
248+
tasks_maximum_percent = 200
249+
propagate_tags = "SERVICE"
250+
tags = merge(local.tags, {
251+
CostOptimization = "fargate-spot"
252+
Service = "fargate-spot-demo"
253+
})
254+
255+
# Service security group rules for direct access (no load balancer)
256+
service_ingress_rules = [
257+
{
258+
from_port = var.containerport
259+
to_port = var.containerport
260+
protocol = "tcp"
261+
description = "HTTP access to fargate spot service"
262+
cidr_blocks = [local.vpc_cidr]
263+
}
264+
]
265+
266+
retention_in_days = var.retention_in_days
267+
}

examples/external-lb/locals.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ locals {
1010
vpc_id = data.aws_vpc.supporting.id
1111
cluster = data.aws_ecs_cluster.ecs.arn
1212
partition = data.aws_partition.current.partition
13-
region = data.aws_region.current.name
13+
region = data.aws_region.current.id
1414
tags = merge({ "Name" = var.name }, var.tags)
1515

1616
default_container_definitions = jsonencode(

examples/fargate/locals.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ locals {
77
vpc_id = data.aws_vpc.supporting.id
88
cluster = data.aws_ecs_cluster.ecs.arn
99
partition = data.aws_partition.current.partition
10-
region = data.aws_region.current.name
10+
region = data.aws_region.current.id
1111
tags = merge({ "Name" = var.name }, var.tags)
1212

1313
default_container_definitions = jsonencode(

locals.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
locals {
22
create_task_definition = var.deployment_controller_type != "EXTERNAL" && var.create_task_definition ? true : false
3-
region = data.aws_region.current.name
3+
region = data.aws_region.current.id
44
partition = data.aws_partition.current.partition
55
account_id = data.aws_caller_identity.current.account_id
66
dns_suffix = data.aws_partition.current.dns_suffix

main.tf

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ resource "aws_ecs_service" "service" {
66
desired_count = var.desired_count
77
deployment_minimum_healthy_percent = var.tasks_minimum_healthy_percent
88
deployment_maximum_percent = var.tasks_maximum_percent
9-
launch_type = var.launch_type
9+
launch_type = length(var.capacity_provider_strategy) > 0 ? null : var.launch_type
1010
enable_execute_command = var.enable_execute_command
1111
force_new_deployment = var.force_new_deployment
1212
triggers = var.triggers
@@ -17,6 +17,15 @@ resource "aws_ecs_service" "service" {
1717
type = var.deployment_controller_type
1818
}
1919

20+
dynamic "capacity_provider_strategy" {
21+
for_each = var.capacity_provider_strategy
22+
content {
23+
capacity_provider = capacity_provider_strategy.value.capacity_provider
24+
weight = capacity_provider_strategy.value.weight
25+
base = capacity_provider_strategy.value.base
26+
}
27+
}
28+
2029
dynamic "network_configuration" {
2130
for_each = var.network_mode == "awsvpc" ? [var.network_configuration] : []
2231
content {

tests/supportingResources/main.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module "ecs_vpc" {
22
source = "boldlink/vpc/aws"
3-
version = "3.0.4"
3+
version = "3.3.0"
44
name = var.name
55
cidr_block = var.cidr_block
66
enable_dns_support = var.enable_dns_support
@@ -46,7 +46,7 @@ resource "aws_cloudwatch_log_group" "cluster" {
4646

4747
module "cluster" {
4848
source = "boldlink/ecs-cluster/aws"
49-
version = "1.1.1"
49+
version = "3.0.0"
5050
name = var.name
5151
tags = local.tags
5252
configuration = {

variables.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,5 +519,24 @@ variable "propagate_tags" {
519519
description = "(Optional) Whether to propagate the tags from the task definition or the service to the tasks. The valid values are SERVICE and TASK_DEFINITION"
520520
type = string
521521
default = "TASK_DEFINITION"
522+
}
522523

524+
variable "capacity_provider_strategy" {
525+
description = <<-EOT
526+
(Optional) Set of capacity provider strategies to use for the service. Can be one or more. List of maps with the following keys:
527+
528+
capacity_provider_strategy = [{
529+
capacity_provider = string # Name of the capacity provider (FARGATE, FARGATE_SPOT, or custom EC2 capacity provider)
530+
weight = number # Relative percentage of the total number of launched tasks that should use the specified capacity provider
531+
base = number # Number of tasks, at a minimum, to run on the specified capacity provider
532+
}]
533+
534+
Note: Cannot be used in conjunction with launch_type. If capacity_provider_strategy is specified, launch_type will be ignored.
535+
EOT
536+
type = list(object({
537+
capacity_provider = string
538+
weight = optional(number, 1)
539+
base = optional(number, 0)
540+
}))
541+
default = []
523542
}

0 commit comments

Comments
 (0)