Examples
These examples demonstrate practical, real-world usage patterns for the ecs-service module. Each example is self-contained and ready to run—simply copy the configuration, customize the values for your environment, and apply.
Getting Started
To run any example, follow these steps:
- Authenticate with the registry:
terraform login registry.patterneddesigns.ca - Initialize the working directory:
terraform init - Review the execution plan:
terraform plan - Apply the configuration:
terraform apply
Usage Examples
Minimal ECS service configuration
module "web_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "web-app"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.web.arn
desired_count = 2
}
ECS service with Application Load Balancer integration
# Create an Application Load Balancer
resource "aws_lb" "main" {
name = "api-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = var.public_subnet_ids
}
resource "aws_lb_target_group" "api" {
name = "api-target-group"
port = 8080
protocol = "HTTP"
vpc_id = var.vpc_id
target_type = "ip"
health_check {
enabled = true
healthy_threshold = 2
interval = 30
matcher = "200"
path = "/health"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 3
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.main.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.api.arn
}
}
# Deploy ECS service with ALB integration
module "api_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "api-service"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.api.arn
desired_count = 3
load_balancer = {
target_group_arn = aws_lb_target_group.api.arn
container_name = "api"
container_port = 8080
}
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
health_check_grace_period_seconds = 60
}
ECS service with auto-scaling policies
# Deploy ECS service with CPU-based auto-scaling
module "scalable_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "worker-service"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.worker.arn
desired_count = 2
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
autoscaling = {
min_capacity = 2
max_capacity = 10
target_cpu_percent = 70
}
}
# Deploy ECS service with memory-based auto-scaling
module "memory_scaled_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "cache-service"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.cache.arn
desired_count = 3
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
autoscaling = {
min_capacity = 3
max_capacity = 20
target_memory_percent = 80
}
}
# Deploy ECS service with request count scaling (ALB)
module "request_scaled_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "api-service"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.api.arn
desired_count = 2
load_balancer = {
target_group_arn = aws_lb_target_group.api.arn
container_name = "api"
container_port = 8080
}
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
autoscaling = {
min_capacity = 2
max_capacity = 50
target_requests_per_target = 1000
scale_in_cooldown = 300
scale_out_cooldown = 60
}
}
ECS service with AWS Cloud Map integration
# Create a private DNS namespace for service discovery
resource "aws_service_discovery_private_dns_namespace" "main" {
name = "internal.example.com"
description = "Private DNS namespace for ECS services"
vpc = var.vpc_id
}
# Deploy backend service with service discovery
module "backend_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "backend"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.backend.arn
desired_count = 2
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
service_discovery = {
namespace_id = aws_service_discovery_private_dns_namespace.main.id
dns_name = "backend"
dns_ttl = 10
routing_policy = "MULTIVALUE"
}
}
# Deploy database service accessible via DNS
module "database_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "redis"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.redis.arn
desired_count = 1
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.redis.id]
assign_public_ip = false
}
service_discovery = {
namespace_id = aws_service_discovery_private_dns_namespace.main.id
dns_name = "redis"
}
}
# Frontend can now connect to:
# - backend.internal.example.com:8080
# - redis.internal.example.com:6379
Blue/green deployment configuration with CodeDeploy
# Create target groups for blue/green deployment
resource "aws_lb_target_group" "blue" {
name = "api-blue"
port = 8080
protocol = "HTTP"
vpc_id = var.vpc_id
target_type = "ip"
health_check {
path = "/health"
healthy_threshold = 2
unhealthy_threshold = 3
}
}
resource "aws_lb_target_group" "green" {
name = "api-green"
port = 8080
protocol = "HTTP"
vpc_id = var.vpc_id
target_type = "ip"
health_check {
path = "/health"
healthy_threshold = 2
unhealthy_threshold = 3
}
}
# Create ALB listeners for production and test traffic
resource "aws_lb_listener" "production" {
load_balancer_arn = aws_lb.main.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.blue.arn
}
lifecycle {
ignore_changes = [default_action]
}
}
resource "aws_lb_listener" "test" {
load_balancer_arn = aws_lb.main.arn
port = 8443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.green.arn
}
lifecycle {
ignore_changes = [default_action]
}
}
# Deploy ECS service with blue/green deployment
module "api_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "api-service"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.api.arn
desired_count = 3
load_balancer = {
target_group_arn = aws_lb_target_group.blue.arn
container_name = "api"
container_port = 8080
}
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
deployment_controller = {
type = "CODE_DEPLOY"
}
blue_green_deployment = {
deployment_config_name = "CodeDeployDefault.ECSLinear10PercentEvery1Minutes"
termination_wait_time_minutes = 5
production_listener_arn = aws_lb_listener.production.arn
test_listener_arn = aws_lb_listener.test.arn
blue_target_group_name = aws_lb_target_group.blue.name
green_target_group_name = aws_lb_target_group.green.name
}
}
Multiple containers in a single task definition
# Task definition with multiple containers
resource "aws_ecs_task_definition" "app" {
family = "app"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 1024
memory = 2048
execution_role_arn = aws_iam_role.execution.arn
task_role_arn = aws_iam_role.task.arn
container_definitions = jsonencode([
{
name = "app"
image = "nginx:latest"
essential = true
portMappings = [
{
containerPort = 80
protocol = "tcp"
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.app.name
awslogs-region = var.region
awslogs-stream-prefix = "app"
}
}
dependsOn = [
{
containerName = "envoy"
condition = "START"
}
]
},
{
name = "envoy"
image = "envoyproxy/envoy:v1.28-latest"
essential = true
portMappings = [
{
containerPort = 9901
protocol = "tcp"
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.app.name
awslogs-region = var.region
awslogs-stream-prefix = "envoy"
}
}
},
{
name = "datadog-agent"
image = "datadog/agent:latest"
essential = false
environment = [
{
name = "DD_API_KEY"
value = var.datadog_api_key
},
{
name = "ECS_FARGATE"
value = "true"
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.app.name
awslogs-region = var.region
awslogs-stream-prefix = "datadog"
}
}
}
])
}
# Deploy multi-container service
module "multi_container_service" {
source = "registry.patterneddesigns.ca/patterneddesigns/ecs-service/aws"
version = "2.0.0"
service_name = "multi-container-app"
cluster_arn = aws_ecs_cluster.main.arn
task_definition_arn = aws_ecs_task_definition.app.arn
desired_count = 2
load_balancer = {
target_group_arn = aws_lb_target_group.app.arn
container_name = "app" # Route traffic to the main app container
container_port = 80
}
network_configuration = {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_tasks.id]
assign_public_ip = false
}
}