diff --git a/main.tf b/main.tf index 795109e..dbba6da 100644 --- a/main.tf +++ b/main.tf @@ -18,6 +18,15 @@ module "ecs_cluster" { use_fargate = var.capacity_provider.use_fargate fargate_capacity_providers = var.capacity_provider.fargate_capacity_providers } + + launch_template = { + name = "lt1" + } + + asg = { + max_size = 2 + min_size = 1 + } } diff --git a/modules/ecs_cluster/main.tf b/modules/ecs_cluster/main.tf index 71286be..a32b589 100644 --- a/modules/ecs_cluster/main.tf +++ b/modules/ecs_cluster/main.tf @@ -81,17 +81,142 @@ resource "aws_ecs_cluster" "this" { tags = merge(var.tags, var.ecs_cluster.tags) } +################################################################################ +# EC2 Launch Template +################################################################################ + +resource "aws_launch_template" "this" { + count = var.capacity_provider.use_fargate != true ? 1 : 0 + + name = var.launch_template.name + + dynamic "block_device_mappings" { + for_each = var.launch_template.block_device_mappings + content { + device_name = block_device_mappings.value.device_name + + dynamic "ebs" { + for_each = block_device_mappings.value.ebs != null ? [block_device_mappings.value.ebs] : [] + content { + volume_size = ebs.value.volume_size + } + } + } + } + + dynamic "cpu_options" { + for_each = var.launch_template.cpu_options != null ? [var.launch_template.cpu_options] : [] + content { + core_count = cpu_options.value.core_count + threads_per_core = cpu_options.value.threads_per_core + } + } + + disable_api_stop = var.launch_template.disable_api_stop + disable_api_termination = var.launch_template.disable_api_termination + ebs_optimized = var.launch_template.ebs_optimized + + dynamic "elastic_gpu_specifications" { + for_each = var.launch_template.elastic_gpu_specifications + content { + type = elastic_gpu_specifications.value.type + } + } + + dynamic "iam_instance_profile" { + for_each = var.launch_template.iam_instance_profile != null ? [var.launch_template.iam_instance_profile] : [] + content { + name = iam_instance_profile.value.name + } + } + + image_id = var.launch_template.image_id + + instance_initiated_shutdown_behavior = var.launch_template.instance_initiated_shutdown_behavior + + dynamic "monitoring" { + for_each = var.launch_template.monitoring != null ? [var.launch_template.monitoring] : [] + content { + enabled = monitoring.value.enabled + } + } + + dynamic "network_interfaces" { + for_each = var.launch_template.network_interfaces + content { + associate_public_ip_address = network_interfaces.value.associate_public_ip_address + ipv4_prefixes = network_interfaces.value.ipv4_prefixes + ipv6_prefixes = network_interfaces.value.ipv6_prefixes + ipv4_addresses = network_interfaces.value.ipv4_addresses + ipv6_addresses = network_interfaces.value.ipv6_addresses + network_interface_id = network_interfaces.value.network_interface_id + private_ip_address = network_interfaces.value.private_ip_address + security_groups = network_interfaces.value.security_groups + subnet_id = network_interfaces.value.subnet_id + } + } + + dynamic "placement" { + for_each = var.launch_template.placement != null ? [var.launch_template.placement] : [] + content { + availability_zone = placement.value.availability_zone + } + } + + vpc_security_group_ids = var.launch_template.vpc_security_group_ids + + dynamic "tag_specifications" { + for_each = var.launch_template.tag_specifications + content { + resource_type = tag_specifications.value.resource_type + tags = tag_specifications.value.tags + } + } + + user_data = var.launch_template.user_data != null ? filebase64(var.launch_template.user_data) : null +} + +################################################################################ +# Auto Scaling Group +################################################################################ + +resource "aws_autoscaling_group" "this" { + count = var.capacity_provider.use_fargate != true ? 1 : 0 + + name = var.asg.name != null ? var.asg.name : "ecs-auto-scaling-group" + min_size = var.asg.min_size + max_size = var.asg.max_size + desired_capacity = var.asg.desired_capacity != null ? var.asg.desired_capacity : var.asg.min_size + vpc_zone_identifier = var.asg.vpc_zone_identifier != null ? var.asg.vpc_zone_identifier : [] + + launch_template { + id = aws_launch_template.this[0].id + } + + health_check_type = var.asg.health_check_type != null ? var.asg.health_check_type : "EC2" + health_check_grace_period = var.asg.health_check_grace_period != null ? var.asg.health_check_grace_period : 300 + protect_from_scale_in = var.asg.protect_from_scale_in != null ? var.asg.protect_from_scale_in : false + default_cooldown = var.asg.default_cooldown != null ? var.asg.default_cooldown : 300 + + instance_refresh { + strategy = var.asg.instance_refresh.strategy + preferences { + min_healthy_percentage = var.asg.instance_refresh.preferences != null && var.asg.instance_refresh.preferences.min_healthy_percentage != null ? var.asg.instance_refresh.preferences.min_healthy_percentage : 50 + } + } +} + ################################################################################ # ECS Capacity Provider - EC2 ################################################################################ resource "aws_ecs_capacity_provider" "this" { - for_each = var.capacity_provider.autoscaling_capacity_providers != null ? var.capacity_provider.autoscaling_capacity_providers : {} + for_each = (var.capacity_provider.use_fargate != true && var.capacity_provider.autoscaling_capacity_providers != null) ? var.capacity_provider.autoscaling_capacity_providers : {} name = each.value.name != "" ? each.value.name : each.key auto_scaling_group_provider { - auto_scaling_group_arn = each.value.auto_scaling_group_arn + auto_scaling_group_arn = aws_autoscaling_group.this[0].arn # Enable managed termination protection only if managed scaling is defined managed_termination_protection = each.value.managed_scaling != null ? (each.value.managed_termination_protection != null ? each.value.managed_termination_protection : "DISABLED") : "DISABLED" diff --git a/modules/ecs_cluster/variables.tf b/modules/ecs_cluster/variables.tf index e21be67..7da391f 100644 --- a/modules/ecs_cluster/variables.tf +++ b/modules/ecs_cluster/variables.tf @@ -56,7 +56,93 @@ EOT } } +variable "launch_template" { + type = object({ + name = string + block_device_mappings = optional(list(object({ + device_name = string + ebs = optional(object({ + volume_size = number + })) + })), []) + + cpu_options = optional(object({ + core_count = number + threads_per_core = number + }), null) + + disable_api_stop = optional(bool, false) + disable_api_termination = optional(bool, false) + ebs_optimized = optional(bool, false) + + elastic_gpu_specifications = optional(list(object({ + type = string + })), []) + + iam_instance_profile = optional(object({ + name = string + }), null) + + image_id = optional(string, null) + instance_initiated_shutdown_behavior = optional(string, "stop") + + instance_type = optional(string, null) + kernel_id = optional(string, null) + key_name = optional(string, null) + + monitoring = optional(object({ + enabled = bool + }), null) + + network_interfaces = optional(list(object({ + associate_public_ip_address = optional(bool, null) + ipv4_prefixes = optional(list(string), []) + ipv6_prefixes = optional(list(string), []) + ipv4_addresses = optional(list(string), []) + ipv6_addresses = optional(list(string), []) + network_interface_id = optional(string, null) + private_ip_address = optional(string, null) + security_groups = optional(list(string), []) + subnet_id = optional(string, null) + })), []) + + placement = optional(object({ + availability_zone = string + }), null) + vpc_security_group_ids = optional(list(string), []) + + tag_specifications = optional(list(object({ + resource_type = string + tags = map(string) + })), []) + + user_data = optional(string, null) + }) +} + +variable "asg" { + description = "Auto Scaling Group configuration" + type = object({ + name = optional(string, null) + min_size = number + max_size = number + desired_capacity = optional(number) + vpc_zone_identifier = optional(list(string)) + + health_check_type = optional(string) + health_check_grace_period = optional(number, 300) + protect_from_scale_in = optional(bool) + default_cooldown = optional(number) + + instance_refresh = optional(object({ + strategy = string + preferences = optional(object({ + min_healthy_percentage = optional(number) + })) + })) + }) +} ################################################################################ # Cluster Capacity Providers diff --git a/variables.tf b/variables.tf index b2462a7..d1b9a87 100644 --- a/variables.tf +++ b/variables.tf @@ -62,6 +62,95 @@ variable "capacity_provider" { } +/* variable "launch_template" { + type = object({ + name = string + block_device_mappings = optional(list(object({ + device_name = string + ebs = optional(object({ + volume_size = number + })) + })), []) + + cpu_options = optional(object({ + core_count = number + threads_per_core = number + }), null) + + disable_api_stop = optional(bool, false) + disable_api_termination = optional(bool, false) + ebs_optimized = optional(bool, false) + + elastic_gpu_specifications = optional(list(object({ + type = string + })), []) + + iam_instance_profile = optional(object({ + name = string + }), null) + + image_id = optional(string, null) + instance_initiated_shutdown_behavior = optional(string, "stop") + + instance_type = optional(string, null) + kernel_id = optional(string, null) + key_name = optional(string, null) + + monitoring = optional(object({ + enabled = bool + }), null) + + network_interfaces = optional(list(object({ + associate_public_ip_address = optional(bool, null) + ipv4_prefixes = optional(list(string), []) + ipv6_prefixes = optional(list(string), []) + ipv4_addresses = optional(list(string), []) + ipv6_addresses = optional(list(string), []) + network_interface_id = optional(string, null) + private_ip_address = optional(string, null) + security_groups = optional(list(string), []) + subnet_id = optional(string, null) + })), []) + + placement = optional(object({ + availability_zone = string + }), null) + + vpc_security_group_ids = optional(list(string), []) + + tag_specifications = optional(list(object({ + resource_type = string + tags = map(string) + })), []) + + user_data = optional(string, null) + }) +} + +variable "asg" { + description = "Auto Scaling Group configuration" + type = object({ + name = optional(string, null) + min_size = number + max_size = number + desired_capacity = optional(number) + vpc_zone_identifier = optional(list(string)) + + health_check_type = optional(string) + health_check_grace_period = optional(number, 300) + protect_from_scale_in = optional(bool) + default_cooldown = optional(number) + + instance_refresh = object({ + strategy = string + preferences = optional(object({ + min_healthy_percentage = optional(number) + })) + }) + }) +} */ + + ################################################################################ ## ALB ################################################################################