Trong bước này, bạn sẽ deploy tất cả infrastructure stacks lên AWS theo đúng thứ tự dependencies. Dự án EveryoneCook sử dụng 5-Stack Architecture với AWS CDK.
Phase 1: DNS Stack → Route 53 Hosted Zone
Phase 1.5: Certificate Stack → ACM Certificates (us-east-1)
Phase 2: Core Stack → DynamoDB, S3, CloudFront, KMS
Phase 3: Auth Stack → Cognito, SES, Lambda Triggers
Phase 4: Backend Stack → API Gateway, Lambda, SQS, WAF
Phase 5: Observability Stack → CloudWatch Dashboards & Alarms
DNS Stack (no dependencies)
↓
Certificate Stack (depends on DNS)
↓
Core Stack (depends on Certificate)
↓
Auth Stack (depends on Core)
↓
Backend Stack (depends on Auth, Core)
↓
Observability Stack (depends on Backend)
| Stack | Time | Critical Resources |
|---|---|---|
| DNS Stack | 2-3 phút | Route 53 Hosted Zone |
| Certificate Stack | 5-10 phút | ACM Certificate (DNS validation) |
| Core Stack | 10-15 phút | CloudFront Distribution, DynamoDB |
| Auth Stack | 5-7 phút | Cognito User Pool, SES |
| Backend Stack | 8-12 phút | API Gateway, 7 Lambda Functions |
| Observability Stack | 3-5 phút | CloudWatch Dashboards |
Total deployment time: 35-50 phút
# Check AWS credentials
aws sts get-caller-identity
# Expected output:
# {
# "UserId": "...",
# "Account": "616580903213",
# "Arn": "arn:aws:iam::616580903213:user/your-username"
# }
# Check Node.js version (must be 20.x+)
node -v
# v20.11.0 or higher
# Check CDK version
cdk --version
# 2.114.0 or higher
# Navigate to infrastructure directory
cd D:\Project_AWS\everyonecook\infrastructure
# Verify cdk.json exists
Get-Item cdk.json
DNS Stack tạo Route 53 Hosted Zone cho domain everyonecook.cloud. Đây là stack đầu tiên và quan trọng nhất.
# Deploy DNS Stack
npx cdk deploy EveryoneCook-dev-DNS --context environment=dev
# Review changes
# Type 'y' to confirm
Expected output:
✅ EveryoneCook-dev-DNS
Outputs:
EveryoneCook-dev-DNS.HostedZoneId = Z018823421GWCSYG5UMHV
EveryoneCook-dev-DNS.HostedZoneName = everyonecook.cloud
EveryoneCook-dev-DNS.NameServers = ns-1164.awsdns-17.org, ns-825.awsdns-39.net, ns-1889.awsdns-44.co.uk, ns-453.awsdns-56.com
Stack ARN:
arn:aws:cloudformation:ap-southeast-1:616580903213:stack/EveryoneCook-dev-DNS/...
LƯU Ý QUAN TRỌNG: Lưu lại 4 nameservers từ output!
# Get nameservers
$nameservers = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-DNS `
--query 'Stacks[0].Outputs[?OutputKey==`NameServers`].OutputValue' `
--output text
Write-Host "Nameservers: $nameservers"
# ns-1164.awsdns-17.org, ns-825.awsdns-39.net, ns-1889.awsdns-44.co.uk, ns-453.awsdns-56.com
Cập nhật nameservers tại domain registrar (Hostinger, GoDaddy, Namecheap, etc.):
ns-1164.awsdns-17.org
ns-825.awsdns-39.net
ns-1889.awsdns-44.co.uk
ns-453.awsdns-56.com
# Check DNS propagation (có thể mất 5-30 phút)
nslookup -type=NS everyonecook.cloud
# Hoặc dùng dig (nếu có WSL/Git Bash)
dig NS everyonecook.cloud
# Expected: Thấy 4 nameservers từ AWS
Online tools để check:
⏳ Đợi DNS propagate trước khi tiếp tục (thường 5-15 phút)
QUAN TRỌNG: Stack này phải deploy ở us-east-1 region vì CloudFront requirement.
# Deploy Certificate Stack (us-east-1)
npx cdk deploy EveryoneCook-dev-Certificate --context environment=dev
# Type 'y' to confirm
Stack tạo 2 certificates:
cdn-dev.everyonecook.cloud*.everyonecook.cloud (wildcard)ACM sẽ tự động:
Quá trình này mất 5-10 phút.
# Check certificate status
aws acm list-certificates --region us-east-1
# Get certificate ARN
$certArn = aws acm list-certificates --region us-east-1 `
--query 'CertificateSummaryList[?DomainName==`cdn-dev.everyonecook.cloud`].CertificateArn' `
--output text
# Check validation status
aws acm describe-certificate --certificate-arn $certArn --region us-east-1 `
--query 'Certificate.{Status:Status,ValidationMethod:DomainValidationOptions[0].ValidationMethod}'
Expected output:
{
"Status": "ISSUED",
"ValidationMethod": "DNS"
}
# List all certificates
aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Certificate `
--region us-east-1 `
--query 'Stacks[0].Outputs'
# Expected:
# CloudFrontCertificateArn = arn:aws:acm:us-east-1:...:certificate/...
# ApiGatewayCertificateArn = arn:aws:acm:us-east-1:...:certificate/...
✅ Chờ đến khi cả 2 certificates có Status = ISSUED
Core Stack tạo foundation resources: DynamoDB, S3, CloudFront, KMS.
# Deploy Core Stack (takes 10-15 minutes)
npx cdk deploy EveryoneCook-dev-Core --context environment=dev
# Type 'y' to confirm
Stack tạo:
DynamoDB:
EveryoneCook-devS3 Buckets (4 buckets):
everyonecook-content-dev - User uploads (avatars, images)everyonecook-logs-dev - S3 access logseveryonecook-cdn-logs-dev - CloudFront logseveryonecook-incoming-emails-dev - SES email receivingCloudFront Distribution:
cdn-dev.everyonecook.cloudKMS Keys (2 keys):
Deployment này mất lâu nhất (10-15 phút) do CloudFront Distribution.
# In another terminal, monitor CloudFormation events
aws cloudformation describe-stack-events `
--stack-name EveryoneCook-dev-Core `
--max-items 10 `
--query 'StackEvents[*].{Time:Timestamp,Status:ResourceStatus,Type:ResourceType,Resource:LogicalResourceId}' `
--output table
# Check DynamoDB table
aws dynamodb describe-table --table-name EveryoneCook-dev `
--query 'Table.{Name:TableName,Status:TableStatus,Billing:BillingModeSummary.BillingMode,Stream:StreamSpecification.StreamEnabled}'
# Expected:
# {
# "Name": "EveryoneCook-dev",
# "Status": "ACTIVE",
# "Billing": "PAY_PER_REQUEST",
# "Stream": true
# }
# Check S3 buckets
aws s3 ls | Select-String "everyonecook"
# Expected:
# everyonecook-cdn-logs-dev
# everyonecook-content-dev
# everyonecook-incoming-emails-dev
# everyonecook-logs-dev
# Check CloudFront distribution
aws cloudfront list-distributions `
--query 'DistributionList.Items[?Comment==`EveryoneCook CDN (dev)`].{Id:Id,Domain:DomainName,Status:Status}'
# Expected:
# {
# "Id": "E2INNJ4XX421Q3",
# "Domain": "d2shrpzup69rju.cloudfront.net",
# "Status": "Deployed"
# }
# Get all Core Stack outputs
aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Core `
--query 'Stacks[0].Outputs[*].{Key:OutputKey,Value:OutputValue}' `
--output table
Key outputs:
DynamoDBTableName: EveryoneCook-devContentBucketName: everyonecook-content-devCloudFrontDistributionId: E2INNJ4XX421Q3CloudFrontDomainName: d2shrpzup69rju.cloudfront.netAuth Stack tạo authentication infrastructure với Cognito và SES.
# Deploy Auth Stack
npx cdk deploy EveryoneCook-dev-Auth --context environment=dev
# Type 'y' to confirm
Stack tạo:
Cognito User Pool:
EveryoneCook-UserPool-dev5 Lambda Triggers:
SES Email Identity:
everyonecook.cloudmail.everyonecook.cloudIAM Roles:
# Get User Pool ID
$userPoolId = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Auth `
--query 'Stacks[0].Outputs[?OutputKey==`UserPoolId`].OutputValue' `
--output text
Write-Host "User Pool ID: $userPoolId"
# ap-southeast-1_PKoL34PF0
# Describe User Pool
aws cognito-idp describe-user-pool --user-pool-id $userPoolId `
--query 'UserPool.{Name:Name,Status:Status,MFA:MfaConfiguration}'
# Check Lambda triggers attached to User Pool
aws cognito-idp describe-user-pool --user-pool-id $userPoolId `
--query 'UserPool.LambdaConfig'
# Expected: 5 triggers configured
# {
# "PreSignUp": "arn:aws:lambda:...:function:EveryoneCook-dev-PreSignup",
# "PostConfirmation": "arn:aws:lambda:...:function:EveryoneCook-dev-PostConfirmation",
# "PostAuthentication": "arn:aws:lambda:...:function:EveryoneCook-dev-PostAuthentication",
# "PreAuthentication": "arn:aws:lambda:...:function:EveryoneCook-dev-PreAuthentication",
# "CustomMessage": "arn:aws:lambda:...:function:EveryoneCook-dev-CustomMessage"
# }
# Check SES identity status
aws sesv2 get-email-identity --email-identity everyonecook.cloud `
--query '{Status:VerifiedForSendingStatus,DKIM:DkimAttributes.Status}'
# Expected:
# {
# "Status": true,
# "DKIM": "SUCCESS"
# }
# Check DKIM records in Route 53
aws route53 list-resource-record-sets `
--hosted-zone-id Z018823421GWCSYG5UMHV `
--query 'ResourceRecordSets[?Type==`CNAME` && contains(Name, `_domainkey`)]'
✅ SES phải ở Production mode để send email đến bất kỳ địa chỉ nào
Backend Stack tạo API Gateway và Lambda functions. Trước khi deploy, cần build Lambda code.
# Navigate to project root
cd D:\Project_AWS\everyonecook
# Run deployment script to build all Lambda code
.\deploy\deploy-backend.ps1 -Environment dev -SkipBuild:$false
# Or manual build:
# Build all modules
cd services/api-router; npm run build; cd ../..
cd services/auth-module; npm run build; cd ../..
cd services/social-module; npm run build; cd ../..
cd services/ai-module; npm run build; cd ../..
cd services/admin-module; npm run build; cd ../..
cd services/upload-module; npm run build; cd ../..
⚠️ QUAN TRỌNG: Lambda code phải được build TRƯỚC khi deploy Backend Stack!
# Navigate back to infrastructure
cd D:\Project_AWS\everyonecook\infrastructure
# Deploy Backend Stack
npx cdk deploy EveryoneCook-dev-Backend --context environment=dev
# Type 'y' to confirm
Stack tạo:
API Gateway:
EveryoneCook-API-devapi-dev.everyonecook.cloud7 Lambda Functions:
everyonecook-dev-api-router - API routing (512 MB, 30s)
everyonecook-dev-auth-user - Auth & User Management (512 MB, 30s)
everyonecook-dev-social - Social features (512 MB, 30s)
everyonecook-dev-recipe-ai - Recipes & AI (1024 MB, 60s)
everyonecook-dev-ai-worker - AI processing worker (1024 MB, 300s)
everyonecook-dev-admin - Admin dashboard (512 MB, 30s)
everyonecook-dev-upload - File upload (256 MB, 15s)
Lambda Layer:
everyonecook-shared-deps-dev - Shared dependencies (~15-20 MB)SQS Queues (4 queues + 4 DLQs):
WAF Web ACL:
# Get API endpoint
$apiUrl = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Backend `
--query 'Stacks[0].Outputs[?OutputKey==`ApiCustomDomain`].OutputValue' `
--output text
Write-Host "API Endpoint: $apiUrl"
# https://api-dev.everyonecook.cloud
# Test health endpoint
$response = Invoke-RestMethod -Uri "$apiUrl/health" -Method Get
$response | ConvertTo-Json
# Expected:
# {
# "status": "healthy",
# "timestamp": "2025-12-09T...",
# "service": "EveryoneCook API",
# "environment": "dev"
# }
# List all Lambda functions
aws lambda list-functions `
--query 'Functions[?contains(FunctionName, `everyonecook-dev`)].{Name:FunctionName,Runtime:Runtime,Memory:MemorySize,Timeout:Timeout}' `
--output table
# Expected: 7 functions + 5 Cognito triggers = 12 Lambda functions total
# List SQS queues
aws sqs list-queues --queue-name-prefix everyonecook-dev
# Expected: 8 queues (4 main + 4 DLQ)
# - everyonecook-dev-ai-queue
# - everyonecook-dev-ai-queue-dlq
# - everyonecook-dev-image-queue
# - everyonecook-dev-image-queue-dlq
# - everyonecook-dev-analytics-queue
# - everyonecook-dev-analytics-queue-dlq
# - everyonecook-dev-notification-queue
# - everyonecook-dev-notification-queue-dlq
Observability Stack tạo monitoring dashboards và alarms.
# Deploy Observability Stack
npx cdk deploy EveryoneCook-dev-Observability --context environment=dev
# Type 'y' to confirm
Stack tạo:
4 CloudWatch Dashboards:
CloudWatch Alarms:
SNS Topic:
Composite Alarm:
# Get SNS topic ARN
$topicArn = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Observability `
--query 'Stacks[0].Outputs[?OutputKey==`AlarmTopicArn`].OutputValue' `
--output text
# Subscribe your email
aws sns subscribe `
--topic-arn $topicArn `
--protocol email `
--notification-endpoint "your-email@example.com"
Write-Host "Check your email and confirm subscription!"
# List CloudWatch dashboards
aws cloudwatch list-dashboards `
--query 'DashboardEntries[?contains(DashboardName, `EveryoneCook-dev`)].DashboardName'
# Expected:
# - EveryoneCook-dev-CoreDashboard
# - EveryoneCook-dev-AuthDashboard
# - EveryoneCook-dev-BackendDashboard
# - EveryoneCook-dev-OverviewDashboard
# Get dashboard URL
$region = "ap-southeast-1"
$dashboardName = "EveryoneCook-dev-OverviewDashboard"
Write-Host "Dashboard URL: https://console.aws.amazon.com/cloudwatch/home?region=$region#dashboards:name=$dashboardName"
# List all deployed stacks
aws cloudformation list-stacks `
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE `
--query 'StackSummaries[?contains(StackName, `EveryoneCook-dev`)].{Name:StackName,Status:StackStatus,Created:CreationTime}' `
--output table
Expected stacks:
------------------------------------------------------------
| ListStacks |
+--------------------------------------------------+--------+
| Name | Status | Created|
+--------------------------------------------------+--------+
| EveryoneCook-dev-DNS | CREATE_COMPLETE |
| EveryoneCook-dev-Certificate | CREATE_COMPLETE |
| EveryoneCook-dev-Core | CREATE_COMPLETE |
| EveryoneCook-dev-Auth | CREATE_COMPLETE |
| EveryoneCook-dev-Backend | CREATE_COMPLETE |
| EveryoneCook-dev-Observability | CREATE_COMPLETE |
+--------------------------------------------------+--------+
# Create comprehensive outputs report
$stacks = @("DNS", "Certificate", "Core", "Auth", "Backend", "Observability")
foreach ($stack in $stacks) {
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "EveryoneCook-dev-$stack Outputs" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
aws cloudformation describe-stacks `
--stack-name "EveryoneCook-dev-$stack" `
--query 'Stacks[0].Outputs[*].{Key:OutputKey,Value:OutputValue}' `
--output table
}
# Save outputs to infrastructure/outputs.json
cd D:\Project_AWS\everyonecook\infrastructure
# Get outputs in JSON format
$outputs = @{}
foreach ($stack in $stacks) {
$stackOutputs = aws cloudformation describe-stacks `
--stack-name "EveryoneCook-dev-$stack" `
--query 'Stacks[0].Outputs' | ConvertFrom-Json
$stackData = @{}
foreach ($output in $stackOutputs) {
$stackData[$output.OutputKey] = $output.OutputValue
}
$outputs["EveryoneCook-dev-$stack"] = $stackData
}
# Save to file
$outputs | ConvertTo-Json -Depth 5 | Out-File -FilePath "outputs.json" -Encoding utf8
Write-Host "Outputs saved to outputs.json" -ForegroundColor Green
# Comprehensive resource verification
Write-Host "`n===== RESOURCE VERIFICATION =====" -ForegroundColor Yellow
# DynamoDB
Write-Host "`nDynamoDB Table:" -ForegroundColor Cyan
aws dynamodb describe-table --table-name EveryoneCook-dev `
--query 'Table.{Name:TableName,Status:TableStatus,ItemCount:ItemCount,Size:TableSizeBytes}' `
--output table
# S3 Buckets
Write-Host "`nS3 Buckets:" -ForegroundColor Cyan
aws s3 ls | Select-String "everyonecook"
# CloudFront
Write-Host "`nCloudFront Distribution:" -ForegroundColor Cyan
aws cloudfront list-distributions `
--query 'DistributionList.Items[?Comment==`EveryoneCook CDN (dev)`].{Id:Id,Status:Status,Domain:DomainName}' `
--output table
# Lambda Functions
Write-Host "`nLambda Functions:" -ForegroundColor Cyan
aws lambda list-functions `
--query 'Functions[?contains(FunctionName, `everyonecook-dev`)].FunctionName' `
--output table
# Cognito User Pool
Write-Host "`nCognito User Pool:" -ForegroundColor Cyan
aws cognito-idp list-user-pools --max-results 10 `
--query 'UserPools[?Name==`EveryoneCook-UserPool-dev`].{Name:Name,Id:Id,Status:Status}' `
--output table
# API Gateway
Write-Host "`nAPI Gateway:" -ForegroundColor Cyan
aws apigateway get-rest-apis `
--query 'items[?name==`EveryoneCook-API-dev`].{Name:name,Id:id}' `
--output table
# SQS Queues
Write-Host "`nSQS Queues:" -ForegroundColor Cyan
aws sqs list-queues --queue-name-prefix everyonecook-dev `
--query 'QueueUrls' --output table
Write-Host "`n===== VERIFICATION COMPLETE =====" -ForegroundColor Green
| Category | Count | Resources |
|---|---|---|
| Networking | 5 | Route 53 Hosted Zone, 2 ACM Certificates, CloudFront Distribution, WAF Web ACL |
| Storage | 6 | DynamoDB Table (5 GSI), 4 S3 Buckets, 2 KMS Keys |
| Compute | 12 | 7 Lambda Functions, 5 Cognito Triggers |
| Integration | 8 | API Gateway, 4 SQS Queues, 4 DLQ |
| Security | 8 | Cognito User Pool, SES Identity, IAM Roles (6) |
| Monitoring | 15 | 4 Dashboards, 10+ Alarms, SNS Topic |
Total Resources: ~100+ AWS resources
DNS Stack:
Certificate Stack:
Core Stack:
Auth Stack:
Backend Stack:
Observability Stack:
# Check CloudFormation events for errors
aws cloudformation describe-stack-events `
--stack-name EveryoneCook-dev-STACKNAME `
--max-items 20 `
--query 'StackEvents[?ResourceStatus==`CREATE_FAILED` || ResourceStatus==`ROLLBACK_IN_PROGRESS`].{Time:Timestamp,Status:ResourceStatus,Reason:ResourceStatusReason,Resource:LogicalResourceId}' `
--output table
# Common causes:
# - Missing dependencies (check dependency order)
# - Insufficient permissions
# - Resource limits exceeded
# - Naming conflicts
# Check certificate status
$certArn = "arn:aws:acm:us-east-1:...:certificate/..."
aws acm describe-certificate --certificate-arn $certArn --region us-east-1 `
--query 'Certificate.DomainValidationOptions[0].{Domain:DomainName,Status:ValidationStatus,Method:ValidationMethod}'
# Check DNS records
aws route53 list-resource-record-sets `
--hosted-zone-id Z018823421GWCSYG5UMHV `
--query 'ResourceRecordSets[?Type==`CNAME`]'
# Solutions:
# - Verify nameservers updated at registrar
# - Wait for DNS propagation (up to 48h, usually 15min)
# - Check validation CNAME records exist in Route 53
# Check if dist folder exists
Get-ChildItem D:\Project_AWS\everyonecook\services\*\dist
# If missing, rebuild
cd D:\Project_AWS\everyonecook
.\deploy\deploy-backend.ps1 -Environment dev
# Check Lambda package size
Get-ChildItem D:\Project_AWS\everyonecook\services\*\lambda.zip |
Select-Object Name, @{Name="Size(MB)";Expression={[math]::Round($_.Length/1MB,2)}}
# Lambda limits:
# - Deployment package: 50 MB (zipped)
# - Unzipped: 250 MB
# Check certificate region (must be us-east-1)
aws acm list-certificates --region us-east-1 `
--query 'CertificateSummaryList[?DomainName==`cdn-dev.everyonecook.cloud`]'
# Check S3 bucket exists
aws s3 ls everyonecook-content-dev
# Solutions:
# - Ensure Certificate Stack deployed first
# - Certificate must be in us-east-1
# - S3 bucket must exist before CloudFront
# Check current user/role
aws sts get-caller-identity
# Required permissions:
# - cloudformation:* (all CloudFormation operations)
# - iam:* (create roles, policies)
# - lambda:* (create functions)
# - apigateway:* (create API)
# - cognito-idp:* (create user pools)
# - s3:* (create buckets)
# - dynamodb:* (create tables)
# - route53:* (create hosted zones)
# - acm:* (create certificates)
# - cloudfront:* (create distributions)
# - wafv2:* (create web ACLs)
# - logs:* (create log groups)
# - sns:* (create topics)
# - sqs:* (create queues)
# Recommended: AdministratorAccess policy (for first deployment)
# If stack rolls back, check reason
aws cloudformation describe-stack-events `
--stack-name EveryoneCook-dev-STACKNAME `
--query 'StackEvents[?ResourceStatus==`CREATE_FAILED`].[Timestamp,ResourceStatusReason]' `
--output table
# Delete failed stack before retry
aws cloudformation delete-stack --stack-name EveryoneCook-dev-STACKNAME
# Wait for deletion
aws cloudformation wait stack-delete-complete --stack-name EveryoneCook-dev-STACKNAME
# Redeploy
npx cdk deploy EveryoneCook-dev-STACKNAME --context environment=dev
| Service | Usage | Cost |
|---|---|---|
| DynamoDB | Pay-per-request, low usage | $2-5 |
| S3 | 10 GB storage + requests | $1-2 |
| CloudFront | 10 GB transfer | $1-2 |
| Lambda | 1M requests, 512 MB | $3-5 |
| API Gateway | 100K requests | $0.35 |
| Cognito | 100 MAU | $0-5 |
| SES | 100 emails | $0.01 |
| CloudWatch | Logs + metrics | $2-3 |
| WAF | Basic rules | $5 |
| Route 53 | 1 hosted zone | $0.50 |
| SQS | 100K requests | $0.04 |
| KMS | 2 keys | $2 |
Total Estimated Monthly Cost: $20-35 (without OpenSearch)
With OpenSearch (if enabled): $70-135/month
# Check current month costs
$startDate = (Get-Date -Day 1).ToString("yyyy-MM-dd")
$endDate = (Get-Date).AddDays(1).ToString("yyyy-MM-dd")
aws ce get-cost-and-usage `
--time-period Start=$startDate,End=$endDate `
--granularity DAILY `
--metrics BlendedCost `
--group-by Type=SERVICE `
--output table
Infrastructure deployment hoàn thành! Tiếp theo:
Current Status:
Proceed to: 5.06 - Configure API & Lambda