Deployment
AWS ECS/Fargate Deployment
Deploy Jiffoo Mall on AWS using ECS and Fargate
AWS ECS/Fargate Deployment
Prerequisites
- AWS CLI 2.0+
- AWS Account with appropriate IAM permissions
- Docker for building images
- ECR repositories created for each service
Architecture Overview
This guide deploys Jiffoo Mall using:
- ECS Fargate for container orchestration
- Application Load Balancer for traffic distribution
- RDS PostgreSQL for database
- ElastiCache Redis for caching
- Secrets Manager for sensitive configuration
Quick Start
1. Create ECR Repositories
aws ecr create-repository --repository-name jiffoo/api
aws ecr create-repository --repository-name jiffoo/shop
aws ecr create-repository --repository-name jiffoo/admin2. Build and Push Images
# Login to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com
# Build and push API
docker build -t jiffoo/api -f apps/api/Dockerfile .
docker tag jiffoo/api:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/api:latest
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/api:latest
# Build and push Shop
docker build -t jiffoo/shop -f apps/shop/Dockerfile .
docker tag jiffoo/shop:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/shop:latest
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/shop:latest
# Build and push Admin
docker build -t jiffoo/admin -f apps/admin/Dockerfile .
docker tag jiffoo/admin:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/admin:latest
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/admin:latest3. Create RDS Database
aws rds create-db-instance \
--db-instance-identifier jiffoo-db \
--db-instance-class db.t3.micro \
--engine postgres \
--engine-version 15.3 \
--master-username postgres \
--master-user-password <your-password> \
--allocated-storage 20 \
--vpc-security-group-ids <security-group-id> \
--db-subnet-group-name <subnet-group-name>4. Create ElastiCache Redis
aws elasticache create-cache-cluster \
--cache-cluster-id jiffoo-redis \
--cache-node-type cache.t3.micro \
--engine redis \
--num-cache-nodes 1 \
--security-group-ids <security-group-id> \
--cache-subnet-group-name <subnet-group-name>ECS Task Definitions
API Task Definition
{
"family": "jiffoo-api",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "api",
"image": "<account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/api:latest",
"portMappings": [
{
"containerPort": 3001,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:jiffoo/database-url"
},
{
"name": "REDIS_URL",
"valueFrom": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:jiffoo/redis-url"
},
{
"name": "JWT_SECRET",
"valueFrom": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:jiffoo/jwt-secret"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/jiffoo-api",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}Shop Task Definition
{
"family": "jiffoo-shop",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "shop",
"image": "<account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/shop:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NEXT_PUBLIC_API_URL",
"value": "https://api.yourdomain.com"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/jiffoo-shop",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}Admin Task Definition
{
"family": "jiffoo-admin",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "admin",
"image": "<account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/admin:latest",
"portMappings": [
{
"containerPort": 3003,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NEXT_PUBLIC_API_URL",
"value": "https://api.yourdomain.com"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/jiffoo-admin",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}Create ECS Services
1. Create ECS Cluster
aws ecs create-cluster --cluster-name jiffoo-cluster2. Register Task Definitions
aws ecs register-task-definition --cli-input-json file://api-task-def.json
aws ecs register-task-definition --cli-input-json file://shop-task-def.json
aws ecs register-task-definition --cli-input-json file://admin-task-def.json3. Create Load Balancers
# Create Application Load Balancer
aws elbv2 create-load-balancer \
--name jiffoo-alb \
--subnets <subnet-id-1> <subnet-id-2> \
--security-groups <security-group-id>
# Create target groups
aws elbv2 create-target-group \
--name jiffoo-api-tg \
--protocol HTTP \
--port 3001 \
--vpc-id <vpc-id> \
--target-type ip \
--health-check-path /health
aws elbv2 create-target-group \
--name jiffoo-shop-tg \
--protocol HTTP \
--port 3000 \
--vpc-id <vpc-id> \
--target-type ip
aws elbv2 create-target-group \
--name jiffoo-admin-tg \
--protocol HTTP \
--port 3003 \
--vpc-id <vpc-id> \
--target-type ip4. Create ECS Services
aws ecs create-service \
--cluster jiffoo-cluster \
--service-name jiffoo-api \
--task-definition jiffoo-api \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[<subnet-id-1>,<subnet-id-2>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" \
--load-balancers "targetGroupArn=<target-group-arn>,containerName=api,containerPort=3001"Secrets Management
Store sensitive configuration in AWS Secrets Manager:
# Database URL
aws secretsmanager create-secret \
--name jiffoo/database-url \
--secret-string "postgresql://postgres:password@<rds-endpoint>:5432/jiffoo"
# Redis URL
aws secretsmanager create-secret \
--name jiffoo/redis-url \
--secret-string "redis://<elasticache-endpoint>:6379"
# JWT Secret
aws secretsmanager create-secret \
--name jiffoo/jwt-secret \
--secret-string "<your-jwt-secret>"Database Migrations
Run migrations using ECS Task:
aws ecs run-task \
--cluster jiffoo-cluster \
--task-definition jiffoo-api \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" \
--overrides '{"containerOverrides":[{"name":"api","command":["pnpm","db:push"]}]}'CloudWatch Logs
View logs for your services:
# API logs
aws logs tail /ecs/jiffoo-api --follow
# Shop logs
aws logs tail /ecs/jiffoo-shop --follow
# Admin logs
aws logs tail /ecs/jiffoo-admin --followScaling
Manual Scaling
aws ecs update-service \
--cluster jiffoo-cluster \
--service jiffoo-api \
--desired-count 4Auto Scaling
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/jiffoo-cluster/jiffoo-api \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 10
# Create scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/jiffoo-cluster/jiffoo-api \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-scaling \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration file://scaling-policy.jsonscaling-policy.json:
{
"TargetValue": 75.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 60
}Monitoring
CloudWatch Dashboards
Create a dashboard to monitor your services:
aws cloudwatch put-dashboard \
--dashboard-name jiffoo-metrics \
--dashboard-body file://dashboard.jsonCloudWatch Alarms
# High CPU alarm
aws cloudwatch put-metric-alarm \
--alarm-name jiffoo-api-high-cpu \
--alarm-description "Alert when API CPU exceeds 80%" \
--metric-name CPUUtilization \
--namespace AWS/ECS \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2Troubleshooting
Service Not Starting
Check service events:
aws ecs describe-services \
--cluster jiffoo-cluster \
--services jiffoo-apiTask Failures
View task details:
aws ecs describe-tasks \
--cluster jiffoo-cluster \
--tasks <task-id>Database Connection Issues
Verify security groups allow traffic from ECS tasks to RDS:
aws ec2 describe-security-groups --group-ids <security-group-id>Container Health Checks
Check target group health:
aws elbv2 describe-target-health \
--target-group-arn <target-group-arn>Cost Optimization
- Use Fargate Spot for non-critical workloads
- Enable ECS Service Auto Scaling to match demand
- Use RDS Reserved Instances for production databases
- Configure CloudWatch Logs retention to reduce storage costs
- Use S3 Lifecycle Policies for old logs and backups
CI/CD Integration
Update your deployment pipeline to push to ECS:
# Build and push new image
docker build -t jiffoo/api -f apps/api/Dockerfile .
docker tag jiffoo/api:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/api:latest
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/jiffoo/api:latest
# Force new deployment
aws ecs update-service \
--cluster jiffoo-cluster \
--service jiffoo-api \
--force-new-deployment