Deploying to AWS ECS with Terraform
ECS with Fargate is the sweet spot between managing servers and going full serverless. Terraform makes it reproducible.
The Stack
Here’s what we need to provision:
| Resource | Purpose |
|---|---|
| VPC | Isolated network |
| Public & private subnets | Multi-AZ placement |
| Security groups | Network access control |
| ECR repository | Container image storage |
| ECS cluster + service | Run containers |
| ALB + target group | Traffic distribution |
Security Groups: Getting Them Right
The key is getting the security groups right — one misconfigured rule and your containers can’t talk to each other, or worse, your database is exposed to the internet.
resource "aws_security_group" "ecs_service" {
name = "ecs-service-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 3000
to_port = 3000
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}The principle: allow the minimum. The ALB security group allows inbound from the internet on 80/443. The ECS security group only allows inbound from the ALB. The database security group only allows inbound from ECS.
Fargate Configuration
Fargate abstracts the EC2 instances. You specify CPU and memory, and AWS handles the rest. For most web services, 0.25 vCPU / 512 MB is a good starting point — scale up based on load testing, not guessing.
CI/CD Integration
After Terraform creates the infrastructure, your CI pipeline needs to:
- Build and tag the Docker image
- Push to ECR
- Update the ECS service with the new task definition
Use a Terraform backend with state locking — S3 + DynamoDB is the standard approach. Without state locking, two people running terraform apply at the same time can corrupt your infrastructure state.
Cost Notes
Fargate is more expensive per vCPU-hour than raw EC2, but you save the operational cost of patching instances and managing capacity. For small-to-medium workloads, the difference is negligible compared to the engineering time saved.