Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ No modules.
| <a name="input_certificate_arn"></a> [certificate\_arn](#input\_certificate\_arn) | ARN of an existing SSL certificate for HTTPS | `string` | `""` | no |
| <a name="input_enable_deletion_protection"></a> [enable\_deletion\_protection](#input\_enable\_deletion\_protection) | Enable or disable deletion protection for the ALB | `bool` | `false` | no |
| <a name="input_enable_https"></a> [enable\_https](#input\_enable\_https) | Enable HTTPS listener (must provide a certificate ARN) | `bool` | `false` | no |
| <a name="input_enable_availability_zone_all"></a> [enable\_availability\_zone\_all](#input\_enable_availability_zone_all) | Set availability_zone to 'all' for IP targets outside VPC | `bool` | `false` | no |
| <a name="input_health_check_healthy_threshold"></a> [health\_check\_healthy\_threshold](#input\_health\_check\_healthy\_threshold) | Number of successful health checks before considering the target healthy | `number` | `3` | no |
| <a name="input_health_check_interval"></a> [health\_check\_interval](#input\_health\_check\_interval) | Health check interval in seconds | `number` | `30` | no |
| <a name="input_health_check_path"></a> [health\_check\_path](#input\_health\_check\_path) | The health check endpoint for ALB target group | `string` | `"/"` | no |
Expand Down
63 changes: 63 additions & 0 deletions example/http-fargate/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

238 changes: 238 additions & 0 deletions example/http-fargate/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
############################################
# Provider Configuration
############################################

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.84.0"
}
}
}

provider "aws" {
region = "ap-southeast-1"
}

############################################
# Data Sources
############################################

data "aws_region" "current" {}
data "aws_availability_zones" "available" {}

data "http" "my_public_ip" {
url = "http://ifconfig.me/ip"
}

############################################
# Random Suffix for Resource Names
############################################

resource "random_string" "suffix" {
length = 8
special = false
upper = false
}

############################################
# Local Variables
############################################

locals {
name = "cltest"
base_name = "${local.name}-${random_string.suffix.result}"

tags = {
Environment = "dev"
Project = "example"
}
}

############################################
# VPC Configuration
############################################

module "vpc" {
source = "tfstack/vpc/aws"

vpc_name = local.base_name
vpc_cidr = "10.0.0.0/16"
availability_zones = slice(data.aws_availability_zones.available.names, 0, 3)

public_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
private_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

eic_subnet = "none"
eic_ingress_cidrs = ["${data.http.my_public_ip.response_body}/32"]

jumphost_instance_create = false
jumphost_subnet = "10.0.0.0/24"
jumphost_log_prevent_destroy = false
create_igw = true
ngw_type = "single"

tags = local.tags
}

############################################
# AWS ALB Module
############################################

module "aws_alb" {
source = "../.."

name = local.base_name
suffix = random_string.suffix.result
vpc_id = module.vpc.vpc_id
public_subnet_ids = module.vpc.public_subnet_ids

enable_https = false
http_port = 80
target_http_port = 80
target_type = "ip"

public_subnet_cidrs = module.vpc.public_subnet_cidrs
}

############################################
# ECS Cluster Configuration
############################################

module "ecs_cluster_fargate" {
source = "tfstack/ecs-cluster-fargate/aws"

# Core Configuration
cluster_name = local.name
suffix = random_string.suffix.result

# VPC Configuration
vpc = {
id = module.vpc.vpc_id
private_subnets = [
for i, subnet in module.vpc.private_subnet_ids :
{ id = subnet, cidr = module.vpc.private_subnet_cidrs[i] }
]
public_subnets = [
for i, subnet in module.vpc.public_subnet_ids :
{ id = subnet, cidr = module.vpc.public_subnet_cidrs[i] }
]
}

# Cluster Settings
cluster_settings = [
{ name = "containerInsights", value = "enabled" }
]

# Logging Configuration
s3_key_prefix = "logs/"
create_cloudwatch_log_group = true
cloudwatch_log_group_retention_days = 90
create_s3_logging_bucket = true

# Capacity Providers
capacity_providers = {
FARGATE = {
default_capacity_provider_strategy = {
weight = 50
base = 20
}
}
FARGATE_SPOT = {
default_capacity_provider_strategy = {
weight = 50
}
}
}

ecs_services = [
{
name = "web-app"
desired_count = 3
cpu = "256"
memory = "512"
force_new_deployment = true

execution_role_policies = [
"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
]

container_definitions = jsonencode([
{
name = "web-app"
image = "nginx:latest"
cpu = 256
memory = 512
essential = true
portMappings = [{
containerPort = 80
}]
healthCheck = {
command = ["CMD-SHELL", "curl -f http://127.0.0.1 || exit 1"]
interval = 30
timeout = 5
retries = 3
startPeriod = 10
}
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = "/aws/ecs/${local.name}-web-app"
awslogs-region = data.aws_region.current.name
awslogs-stream-prefix = "${local.name}-nginx"
}
}
}
])

deployment_minimum_healthy_percent = 100
deployment_maximum_percent = 200
health_check_grace_period_seconds = 30

subnet_ids = module.vpc.private_subnet_ids
security_groups = [aws_security_group.ecs.id]
assign_public_ip = false

enable_alb = true
enable_ecs_managed_tags = true
propagate_tags = "TASK_DEFINITION"

service_tags = {
Environment = "staging"
Project = "WebApp"
Owner = "DevOps"
}

task_tags = {
TaskType = "backend"
Version = "1.0"
}
}
]

ecs_autoscaling = [
{
service_name = "${local.name}-web-app"
min_capacity = 3
max_capacity = 12
scalable_dimension = "ecs:service:DesiredCount"
policy_name = "scale-on-cpu"
policy_type = "TargetTrackingScaling"
target_value = 75
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
]

tags = local.tags
}

############################################
# Outputs
############################################

output "all_module_outputs" {
description = "All outputs from the ALB module"
value = module.aws_alb
}
24 changes: 13 additions & 11 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ resource "aws_security_group" "this" {
resource "aws_lb_target_group" "http" {
count = var.enable_https ? 0 : 1

name = "${local.base_name}-http"
port = var.target_http_port
protocol = "HTTP" # var.target_protocol
vpc_id = var.vpc_id
name = "${local.base_name}-http"
port = var.target_http_port
protocol = "HTTP" # var.target_protocol
target_type = var.target_type
vpc_id = var.vpc_id

health_check {
path = var.health_check_path
Expand All @@ -84,11 +85,12 @@ resource "aws_lb_target_group" "http" {

# HTTPS Target Group (Only created if HTTPS is enabled)
resource "aws_lb_target_group" "https" {
count = var.enable_https ? 1 : 0
name = "${local.base_name}-https"
port = var.target_https_port
protocol = "HTTPS" # var.target_protocol
vpc_id = var.vpc_id
count = var.enable_https ? 1 : 0
name = "${local.base_name}-https"
port = var.target_https_port
protocol = "HTTPS" # var.target_protocol
target_type = var.target_type
vpc_id = var.vpc_id

health_check {
path = var.health_check_path
Expand Down Expand Up @@ -170,8 +172,8 @@ resource "aws_lb_target_group_attachment" "generic" {
target_id = each.value

# Ensure port is only applied for instance and IP targets
port = var.target_type == "instance" || var.target_type == "ip" ? var.target_http_port : null
port = contains(["instance", "ip"], var.target_type) ? var.target_http_port : null

# Ensure availability zone is applied only for IP targets outside VPC
availability_zone = var.target_type == "ip" && !contains(var.public_subnet_cidrs, each.value) ? "all" : null
availability_zone = var.enable_availability_zone_all ? "all" : null
}
11 changes: 9 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,11 @@ variable "certificate_arn" {
variable "targets" {
description = "List of targets (EC2 instance IDs, IPs, Lambda ARNs, or ALB ARNs)"
type = list(string)
default = []

validation {
condition = length(var.targets) > 0
error_message = "At least one target must be specified."
condition = var.target_type == "ip" || length(var.targets) > 0
error_message = "At least one target must be specified unless target_type is 'ip'."
}
}

Expand All @@ -162,3 +163,9 @@ variable "target_type" {
error_message = "Allowed values for target_type are 'instance', 'ip', 'lambda', or 'alb'."
}
}

variable "enable_availability_zone_all" {
description = "Set availability_zone to 'all' for IP targets outside VPC"
type = bool
default = false
}