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:

  1. Authenticate with the registry: terraform login registry.patterneddesigns.ca
  2. Initialize the working directory: terraform init
  3. Review the execution plan: terraform plan
  4. Apply the configuration: terraform apply

Usage Examples

Basic Usage

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
}

With ALB

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
}

Auto-Scaling

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
  }
}

Service Discovery

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

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
  }
}

Multi-Container Task

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
  }
}