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