Convert all poet attribution lines to use an em dash, English name format, and consistent spacing. Re-indent the blog single page template for readability and adjust the typewriter element layout.
77 lines
2.6 KiB
Markdown
77 lines
2.6 KiB
Markdown
---
|
||
title: "Deploying to AWS ECS with Terraform"
|
||
date: 2026-05-14T10:00:00+08:00
|
||
draft: false
|
||
poet: |
|
||
If you have built castles in the air,
|
||
your work need not be lost;
|
||
that is where they should be.
|
||
Now put the foundations under them.
|
||
— Henry David Thoreau, US, 1817–1862
|
||
description: "Infrastructure as code from scratch: VPC, subnets, security groups, ECR repository, ECS service with Fargate, and an ALB in front. Every resource explained."
|
||
tags:
|
||
- AWS
|
||
- Terraform
|
||
- DevOps
|
||
---
|
||
|
||
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.
|
||
|
||
```hcl
|
||
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:
|
||
|
||
1. Build and tag the Docker image
|
||
2. Push to ECR
|
||
3. 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.
|