Build a Production-Grade AWS ECS Fargate Cluster with Terraform (Modular, Scalable & CI/CD-Ready)

Project Goal

Design and provision a production-grade, reusable, and modular ECS Fargate infrastructure using Terraform, with best practices around:

  • βœ… Zero-downtime deployments using ALB with rolling updates

  • πŸ” Secure networking across public/private subnets, NAT Gateways, and Security Groups

  • πŸ“Š Observability and centralized logging using Amazon CloudWatch Logs

  • βš–οΈ Auto-scaling via ECS capacity providers and intelligent health checks

  • πŸ“ IaC-based consistency across dev/staging/prod environments

  • πŸ” Built for CI/CD, secrets management, and service discovery

  • 🧱 Acts as a foundation to deploy any modern containerized app (monoliths or microservices)


πŸ”— GitHub Repository

πŸ‘‰ terraform-aws-ecs-fargate-infra: https://github.com/neamulkabiremon/terraform-aws-ecs-fargate-infra.git


🧰 Tech Stack

  • Terraform β€” Infrastructure as Code

  • AWS ECS (Fargate) β€” Serverless container orchestration

  • Amazon ECR β€” Container image registry

  • Application Load Balancer (ALB) β€” HTTP-based traffic routing

  • AWS IAM β€” Roles and permission boundaries

  • CloudWatch Logs β€” Container observability

  • Docker β€” Local development & containerization

  • AWS CLI / Console β€” Manual validation


πŸ“ Project Structure

Project Structure
β”œβ”€β”€ backend.tf                 # Terraform backend config (S3 + DynamoDB for remote state)
β”œβ”€β”€ main.tf                    # Root Terraform config to orchestrate module calls
β”œβ”€β”€ outputs.tf                 # Outputs from various modules (e.g., ALB DNS, VPC ID)
β”œβ”€β”€ variables.tf               # Global variables used across modules
β”œβ”€β”€ modules/                   # Reusable infrastructure modules
β”‚   β”œβ”€β”€ vpc/                   # VPC, subnets, NAT, and route tables
β”‚   β”œβ”€β”€ alb/                   # Application Load Balancer, target group, listener
β”‚   β”œβ”€β”€ ecs_cluster/           # ECS Cluster setup with Fargate providers
β”‚   β”œβ”€β”€ ecs_service/           # ECS service configuration (task count, deployment)
β”‚   β”œβ”€β”€ ecs_task_definition/   # Task definitions (image, container config, logging)
β”‚   β”œβ”€β”€ iam_roles/             # IAM roles and custom policies for ECS tasks

Each module is self-contained, with its own main.tf, variables.tf, and outputs.tf, making the architecture modular, reusable, and maintainable.


🌐 Virtual Private Cloud Setup

modules/vpc/ β€”

This module provisions:

  • A VPC with the CIDR block 10.0.0.0/16

  • 2 Public + 2 Private subnets spread across multiple Availability Zones (AZs) for high availability

  • NAT Gateways in public subnets to allow outbound internet access from private subnets

  • Route tables and subnet associations

  • Used by ALB (public subnet) and ECS tasks (private subnet)


🌍 Application Load Balancer

modules/alb/ β€”

This module provisions:

  • An Application Load Balancer in the public subnets

  • Target Group in ip mode (for Fargate)

  • Listener on port 80 forwarding to the target group

  • Health checks to ensure traffic only routes to healthy ECS tasks

  • Integrated with ECS service to route HTTP requests to the right container


πŸͺ€ ECS Cluster (Fargate)

modules/ecs_cluster/

This module provisions:

  • An ECS Cluster with Fargate and Fargate Spot capacity providers

  • Container Insights enabled for metrics and observability

  • Acts as the compute backend for all services deployed via ECS


🧠 Task Definition

modules/ecs_task_definition/ β€”

This module defines:

  • The Docker container configuration for a service (e.g., nginx, or any custom app)

  • CPU, memory, container port, logging config (to CloudWatch), and health checks

  • IAM roles: execution and task roles

  • Uses awsvpc network mode (required for Fargate)


πŸš€ ECS Service

modules/ecs_service/β€”

This module provisions:

  • The actual ECS service tied to the cluster and task definition

  • Auto-registers with the target group in the ALB

  • Uses rolling deployment, circuit breakers, and health checks

  • Launches tasks in private subnets with correct security group


πŸ” IAM Roles and Policies

modules/iam_roles/ β€”

This module sets up:

  • Task Execution Role: Grants ECS permission to pull images (from ECR), send logs (to CloudWatch), and fetch secrets

  • Task Role: Customizable permissions for containers (e.g., access to S3, DynamoDB)

  • Supports attaching managed or custom inline policies


πŸ“Š CloudWatch Integration

  • ECS logs (from tasks) are shipped to CloudWatch Logs

  • Example log group: /ecs/my-app

  • Helps with observability, debugging, and audit trails

  • Terraform provisions log groups automatically

πŸ” Setup Secure Backend

Before provisioning the infrastructure, configure remote state management using Amazon S3 (for storing state) and DynamoDB (for state locking and consistency).

This allows:

  • Team collaboration with shared state

  • Preventing concurrent terraform apply

  • Version-controlled and recoverable infrastructure state

1. Create the S3 Bucket

Use the AWS CLI or Console to create the S3 bucket that will hold your Terraform state:

aws s3api create-bucket \
  --bucket my-ecs-terraform-state \
  --region us-east-1

Enable versioning for safety:

aws s3api put-bucket-versioning \
  --bucket my-ecs-terraform-state \
  --versioning-configuration Status=Enabled

2. Create the DynamoDB Table for Locking

Create a DynamoDB table to manage state locks and avoid race conditions:

aws dynamodb create-table \
  --table-name terraform-locks \
  --attribute-definitions AttributeName=LockID,AttributeType=S \
  --key-schema AttributeName=LockID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

3. Configure the Backend in

backend.tf

Add this snippet to your backend.tf:

Replace the bucket and dynamodb_table values with the names of your actual S3 bucket and DynamoDB table that you created for backend state management.

terraform {
  backend "s3" {
    bucket         = "my-ecs-terraform-state"     # πŸ‘ˆ Your S3 bucket name
    key            = "ecs/terraform.tfstate"      # πŸ‘ˆ Path to store the state file
    region         = "us-east-1"                  # πŸ‘ˆ Bucket region
    dynamodb_table = "terraform-locks"            # πŸ‘ˆ Locking table name
    encrypt        = true                         # πŸ‘ˆ Server-side encryption enabled
  }
}

πŸ’‘ On the first terraform init, you’ll be asked to confirm migrating state to the remote backend.

πŸš€ Final Deployment Steps (Terraform + ECS + Docker Image)

βœ… 1. Declare All Required Variables (in variables.tf)

Ensure that your ECS task definition is fully configured with the correct Docker image, container name, port mappings, CPU, memory, and logging settings before deployment.

variable "container_name" {
  description = "Name of the container"
  type        = string
  default     = "crypto-app"
}

variable "container_image" {
  description = "Docker image to deploy"
  type        = string
  default     = "377027906194.dkr.ecr.us-east-1.amazonaws.com/crypto-project:ba75ec4"
}

variable "container_port" {
  description = "Port the container listens on"
  type        = number
  default     = 5000
}

variable "desired_count" {
  description = "Number of ECS tasks to run"
  type        = number
  default     = 2
}

variable "cpu" {
  description = "CPU units for the ECS task"
  type        = number
  default     = 256
}

variable "memory" {
  description = "Memory (in MiB) for the ECS task"
  type        = number
  default     = 512
}

variable "region" {
  description = "AWS region to deploy resources"
  type        = string
  default     = "us-east-1"
}

variable "environment" {
  description = "Environment name (e.g., dev, staging, prod)"
  type        = string
  default     = "dev"
}

βœ… 2. Initialize Terraform

terraform init

πŸ”Ή This sets up your backend (S3, DynamoDB), downloads providers, and initializes all modules.

βœ… 3. Apply the Infrastructure

terraform apply -auto-approve

This will provision everything: VPC, ECS, ALB, IAM roles, etc. Confirm the action by typing yes when prompted.

βœ… You’ll see something like:

alb_endpoint = "ecs-alb-1159466113.us-east-1.elb.amazonaws.com"

Give it a minute or two ⏳ for the DNS and load balancer to fully initialize.

πŸ”— Then open the URL in your browser β€” no console digging required.

http://ecs-alb-1159466113.us-east-1.elb.amazonaws.com/

πŸš€ And boom β€” your app is up and running! 🟒

Head to the ALB URL and login using the credentials below:

Username: admin Password: password123

βœ… You’ve just deployed a secure, scalable ECS app using Terraform like a pro!

πŸ”„ What’s Next?

Now that your production-ready ECS infrastructure is live, here are some powerful enhancements to take it to the next level:

  • βœ… CI/CD Integration

    Automate deployments using GitHub Actions or AWS CodePipeline for faster iteration and safer releases.

  • πŸ” HTTPS & Domain Configuration

    Use AWS ACM and Route 53 to secure your services with SSL certificates and custom domains.

  • πŸ”‘ Secrets Management

    Store sensitive credentials like API keys or DB passwords securely using AWS Secrets Manager.

  • πŸ“ˆ Autoscaling

    Define autoscaling policies to handle traffic spikes and optimize cost by scaling ECS tasks dynamically.

  • 🧭 Service Discovery

    For multi-service architecture, implement Cloud Map or internal ALB routing to enable service-to-service communication.


πŸš€ Final Thoughts

With this Terraform-based setup, you now have:

βœ… Modular Infrastructure β€” Easy to extend or replicate across dev/staging/prod

βœ… Scalability β€” ECS Fargate with capacity providers for high availability

βœ… Security β€” Isolated networks, IAM policies, and encrypted backend

βœ… Observability β€” CloudWatch Logs integrated for real-time monitoring

βœ… Reusability β€” Each module is built to be reused across multiple projects

Whether you’re deploying a single service or managing a suite of microservices, this infrastructure gives you a rock-solid, production-ready foundation.


πŸ‘‹ Source Code Available

πŸ‘‰ GitHub – terraform-aws-ecs-fargate-infra

Feel free to explore the repo, give it a ⭐️, or fork it for your next cloud-native deployment.


πŸ’¬ Let’s Connect

Have questions, feedback, or ideas?

Drop a comment or send me a DM β€” I’d love to hear from you

Linkedin: https://www.linkedin.com/in/neamul-kabir-emon/

0
Subscribe to my newsletter

Read articles from Neamul Kabir Emon directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Neamul Kabir Emon
Neamul Kabir Emon

Hi! I'm a highly motivated Security and DevOps professional with 7+ years of combined experience. My expertise bridges penetration testing and DevOps engineering, allowing me to deliver a comprehensive security approach.