Production-ready AWS infrastructure for deploying containerized applications using ECS Fargate, Application Load Balancer, and automated CI/CD with GitHub Actions.
Internet
β
βββ Route 53 (optional)
β
βββ ACM Certificate (HTTPS)
β
βββ Application Load Balancer (Public Subnets)
β ββ HTTP β HTTPS redirect
β ββ HTTPS β ECS Tasks
β
βββ ECS Fargate Tasks (Private Subnets)
ββ Auto-scaling (1-4 tasks)
ββ CloudWatch Logs
ββ NAT Gateway β Internet (outbound)
Supporting Infrastructure:
- ECR: Container image registry
- IAM: Task execution and application roles
- Security Groups: ALB and ECS isolation
- DynamoDB: Terraform state locking
- Terraform: >= 1.5.0
- AWS CLI: Configured with credentials
- Docker: For building and pushing container images
- Git: For version control
- GitHub Account: For CI/CD (optional)
git clone <your-repo-url>
cd aws-terraformUpdate variables.tf or create terraform.tfvars:
profile = "admin_vinicius_ferreira" # Your AWS CLI profile
region = "us-east-1"terraform initFor development environment:
# Plan
terraform plan -var-file=environments/dev.tfvars
# Apply
terraform apply -var-file=environments/dev.tfvars# Get ECR repository URL from Terraform outputs
ECR_REPO=$(terraform output -raw ecr_repository_url)
# Login to ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REPO
# Build and push
docker build -t my-app .
docker tag my-app:latest $ECR_REPO:latest
docker push $ECR_REPO:latestUpdate environments/dev.tfvars:
container_image = "<ecr-repository-url>:latest"Then apply again:
terraform apply -var-file=environments/dev.tfvars# Get ALB URL
terraform output alb_urlVisit the URL in your browser!
.
βββ modules/
β βββ ecr/ # Container registry
β βββ networking/ # VPC, subnets, NAT
β βββ security-groups/ # ALB and ECS security groups
β βββ iam/ # ECS task roles
β βββ alb/ # Application Load Balancer
β βββ ecs/ # ECS Fargate cluster and service
βββ environments/
β βββ dev.tfvars # Development configuration
β βββ staging.tfvars # Staging configuration
β βββ prod.tfvars # Production configuration
βββ docs/
β βββ architecture.md # Architecture details
β βββ deployment.md # Deployment guide
β βββ runbook.md # Operations runbook
βββ .github/
β βββ workflows/
β βββ terraform.yml # CI/CD pipeline
βββ main.tf # Main infrastructure
βββ variables.tf # Input variables
βββ outputs.tf # Output values
βββ versions.tf # Terraform and provider versions
βββ locals.tf # Local values
βββ acm.tf # ACM certificate (optional)
βββ iam-github-actions.tf # GitHub OIDC for CI/CD
- Container image registry
- Image scanning enabled
- Lifecycle policy (keep last 10 images)
- VPC with public and private subnets
- Internet Gateway for public subnets
- NAT Gateway for private subnet outbound traffic
- Multi-AZ deployment (us-east-1a, us-east-1b)
- ALB security group (allow 80/443 from internet)
- ECS security group (allow traffic from ALB only)
- Task execution role (ECR pull, CloudWatch Logs)
- Task role (application permissions)
- Internet-facing Application Load Balancer
- HTTP β HTTPS redirect
- Health checks for ECS tasks
- ECS Fargate cluster
- Task definition with configurable CPU/memory
- ECS service with ALB integration
- Auto-scaling based on CPU and memory
- CloudWatch logging
- 1 task (256 CPU, 512 MB memory)
- HTTP only (no HTTPS)
- Minimal auto-scaling (1-2 tasks)
- 7-day log retention
- ECS Exec enabled for debugging
- 2 tasks (512 CPU, 1024 MB memory)
- Optional HTTPS
- Moderate auto-scaling (2-4 tasks)
- 14-day log retention
- 2+ tasks (512 CPU, 1024 MB memory)
- HTTPS required
- Aggressive auto-scaling (2-10 tasks)
- 30-day log retention
- Deletion protection enabled
- ECS Exec disabled
-
Create GitHub OIDC provider and role:
# Update iam-github-actions.tf with your GitHub repo # Then apply terraform apply
-
Add GitHub secrets:
AWS_REGION:us-east-1AWS_ROLE_ARN: (from terraform output)
-
Configure environment protection (Settings > Environments):
- Create "production" environment
- Add required reviewers
- Push to PR: Runs
terraform fmt,validate, andplan - Merge to main: Runs
terraform apply(requires approval) - Plan output is posted as PR comment
Monthly costs (us-east-1, dev environment):
| Resource | Cost |
|---|---|
| NAT Gateway | ~$32 + data transfer |
| Application Load Balancer | ~$16 + LCU |
| ECS Fargate (1 task, 0.25 vCPU, 0.5 GB) | ~$7.50 |
| CloudWatch Logs | ~$5 |
| ECR Storage | ~$1 |
| Total | ~$65-100/month |
- Use single NAT Gateway (saves ~$32/month)
- Scale down during off-hours
- Reduce log retention
- Right-size tasks based on actual usage
- Consider Fargate Spot for non-critical workloads (70% savings)
- β ECS tasks in private subnets (no direct internet access)
- β Security groups with least privilege
- β Separate IAM roles for execution and application
- β Secrets via AWS Secrets Manager
- β ECR image scanning enabled
- β HTTPS with ACM certificates (production)
- β CloudWatch logging enabled
- β State locking with DynamoDB
- β OIDC for GitHub Actions (no hardcoded credentials)
# Tail logs
aws logs tail /ecs/dev-app --follow
# Query logs
aws logs filter-log-events \
--log-group-name /ecs/dev-app \
--filter-pattern "ERROR"# Describe service
aws ecs describe-services \
--cluster dev-cluster \
--services dev-app-service
# List tasks
aws ecs list-tasks --cluster dev-cluster
# Describe task
aws ecs describe-tasks \
--cluster dev-cluster \
--tasks <task-id># Check target health
aws elbv2 describe-target-health \
--target-group-arn <target-group-arn># Check service events
aws ecs describe-services --cluster <cluster> --services <service>
# Check task stopped reason
aws ecs describe-tasks --cluster <cluster> --tasks <task-id>Common issues:
- Invalid container image
- Insufficient IAM permissions
- Health check failures
- Resource constraints
- Ensure your app responds with HTTP 200 on health check path
- Check application logs in CloudWatch
- Verify security groups allow ALB β ECS traffic
- Increase health check timeout if app is slow to start
- Check CloudWatch metrics for unused resources
- Review auto-scaling settings
- Consider scaling down during off-hours
- Reduce log retention
- Use Fargate Spot for non-critical workloads
- Architecture Details
- Deployment Guide
- Operations Runbook
- AWS ECS Documentation
- Terraform AWS Provider
- Fork the repository
- Create a feature branch
- Make your changes
- Run
terraform fmt -recursive - Submit a pull request
This project is for educational purposes.
Vinicius Ferreira - Rocketseat AWS Study Program
- Rocketseat AWS Study Program
- Terraform AWS Provider Team
- AWS Documentation