Sau khi deploy infrastructure với CDK, bạn cần deploy Lambda code lên AWS. Dự án EveryoneCook cung cấp automated deployment script để build, package và deploy tất cả Lambda functions.
Lambda Modules (7 functions):
api-router - API Gateway routing với JWT validationauth-user - Authentication & User Managementsocial - Posts, Comments, Reactions, Friends, Notificationsrecipe-ai - Recipes & AI Features (Bedrock)ai-worker - Async AI processing workeradmin - Admin Dashboard & Content Moderationupload - File Upload với S3 Presigned URLsLambda Layer:
shared-dependencies - Shared npm packages (aws-sdk, uuid, etc.)Cognito Triggers (Auth Stack):
1. Build Lambda Layer (shared dependencies)
2. Build TypeScript modules → JavaScript
3. Validate dist folders (check for issues)
4. Prepare deployment packages
5. Deploy via CDK hoặc Direct Lambda Update
6. Verify deployments
7. Check CloudWatch logs
Full deployment sử dụng CDK để deploy toàn bộ infrastructure và Lambda code.
# Navigate to everyonecook root
cd D:\Project_AWS\everyonecook
# Full deployment cho dev environment
.\deploy\deploy-backend.ps1 -Environment dev
# Hoặc ngắn gọn (default là dev)
.\deploy\deploy-backend.ps1
Script sẽ thực hiện:
STEP 0: Building Lambda Layer
layers/shared-dependencies/nodejs/STEP 1: Building Lambda modules
STEP 2: Validating dist folders
STEP 3: Preparing deployment packages
STEP 4: Deploy with CDK
EveryoneCook-dev-Backend stackOutput mẫu:
========================================
Backend Deployment - dev
With Lambda Layers
========================================
STEP 0: Building Lambda Layer...
Installing layer dependencies...
Layer built: 18.45 MB
STEP 1: Building Lambda modules...
Building auth triggers... OK
Building api-router... OK
Building auth-module... OK
Building social-module... OK
Building ai-module... OK
Building admin-module... OK
Building upload-module... OK
STEP 2: Validating dist folders...
api-router... OK (125 files, 1.2 MB)
auth-module... OK (156 files, 1.5 MB)
social-module... OK (189 files, 1.8 MB)
ai-module... OK (142 files, 1.3 MB)
admin-module... OK (98 files, 0.9 MB)
upload-module... OK (45 files, 0.4 MB)
STEP 3: Preparing deployment packages...
Preparing api-router... Done
Preparing auth-module... Done
Preparing social-module... Done
Preparing ai-module... Done
Preparing admin-module... Done
Preparing upload-module... Done
STEP 4: Deploying with CDK...
Synthesizing CloudFormation templates...
EveryoneCook-dev-Backend
Deploying...
✅ Lambda Layer updated
✅ API Router function updated
✅ Auth User function updated
✅ Social function updated
✅ Recipe AI function updated
✅ AI Worker updated
✅ Admin function updated
✅ Upload function updated
Outputs:
ApiUrl = https://xinq7xh300.execute-api.ap-southeast-1.amazonaws.com/v1/
ApiCustomDomain = https://api-dev.everyonecook.cloud
========================================
FULL DEPLOYMENT SUCCESSFUL!
========================================
# List all Lambda functions
aws lambda list-functions `
--query 'Functions[?contains(FunctionName, `everyonecook-dev`)].{Name:FunctionName,Runtime:Runtime,Updated:LastModified}' `
--output table
# Expected output:
# --------------------------------------------------------
# | ListFunctions |
# +------------------------------------------------------+
# | Name | Runtime | Updated |
# +------------------------------------------------------+
# | everyonecook-dev-api-router | nodejs20.x | ... |
# | everyonecook-dev-auth-user | nodejs20.x | ... |
# | everyonecook-dev-social | nodejs20.x | ... |
# | everyonecook-dev-recipe-ai | nodejs20.x | ... |
# | everyonecook-dev-ai-worker | nodejs20.x | ... |
# | everyonecook-dev-admin | nodejs20.x | ... |
# | everyonecook-dev-upload | nodejs20.x | ... |
# +------------------------------------------------------+
Nếu chỉ thay đổi Lambda code (không thay đổi infrastructure), dùng fast deployment.
# Fast deploy - chỉ update Lambda code
.\deploy\deploy-backend.ps1 -Environment dev -LambdaOnly
# Hoặc dùng dedicated script
.\deploy\force-update-lambdas.ps1 -Environment dev
Faster deployment process:
STEP 0: Build Layer (hoặc skip)
STEP 1: Build modules
STEP 2: Validate dist
STEP 3: Prepare packages
STEP 4: Upload to Lambda (Fast Deploy)
- Create ZIP files
- Upload directly via aws lambda update-function-code
- Update Layer ARN if changed
- Skip CDK (faster)
Thời gian:
# Skip layer build (dùng existing layer)
.\deploy\deploy-backend.ps1 -Environment dev -SkipLayer
# Skip module build (dùng existing dist)
.\deploy\deploy-backend.ps1 -Environment dev -SkipBuild
# Combine options
.\deploy\deploy-backend.ps1 -Environment dev -LambdaOnly -SkipLayer
# Get API Router details
aws lambda get-function `
--function-name everyonecook-dev-api-router `
--query 'Configuration.{Runtime:Runtime,Handler:Handler,Timeout:Timeout,Memory:MemorySize,Layer:Layers[0].Arn}'
# Expected output:
# {
# "Runtime": "nodejs20.x",
# "Handler": "services/api-router/dist/handlers/index.handler",
# "Timeout": 30,
# "Memory": 512,
# "Layer": "arn:aws:lambda:ap-southeast-1:...:layer:everyonecook-shared-deps-dev:X"
# }
# Check code hash
aws lambda get-function `
--function-name everyonecook-dev-api-router `
--query 'Configuration.CodeSha256'
# SHA256 sẽ thay đổi mỗi khi code update
# Get environment variables
aws lambda get-function-configuration `
--function-name everyonecook-dev-auth-user `
--query 'Environment.Variables'
# Expected:
# {
# "TABLE_NAME": "EveryoneCook-dev",
# "REGION": "ap-southeast-1",
# "USER_POOL_ID": "ap-southeast-1_PKoL34PF0",
# ...
# }
# Invoke API Router với test event
aws lambda invoke `
--function-name everyonecook-dev-api-router `
--payload '{"httpMethod":"GET","path":"/health","headers":{}}' `
response.json
# Check response
Get-Content response.json | ConvertFrom-Json
# Expected:
# {
# "statusCode": 200,
# "body": "{\"status\":\"healthy\",\"timestamp\":\"...\"}"
# }
# Warm up all functions
$functions = @(
"everyonecook-dev-api-router",
"everyonecook-dev-auth-user",
"everyonecook-dev-social",
"everyonecook-dev-recipe-ai",
"everyonecook-dev-admin",
"everyonecook-dev-upload"
)
foreach ($func in $functions) {
Write-Host "Warming up $func..." -ForegroundColor Cyan
aws lambda invoke `
--function-name $func `
--payload '{"warmup":true}' `
out.json | Out-Null
}
Write-Host "All functions warmed up!" -ForegroundColor Green
# Tail API Router logs
aws logs tail /aws/lambda/everyonecook-dev-api-router --follow
# View last 10 minutes
aws logs tail /aws/lambda/everyonecook-dev-api-router --since 10m
# Search for errors in last hour
$oneHourAgo = [DateTimeOffset]::Now.AddHours(-1).ToUnixTimeMilliseconds()
aws logs filter-log-events `
--log-group-name /aws/lambda/everyonecook-dev-api-router `
--start-time $oneHourAgo `
--filter-pattern "ERROR"
# List all log groups
aws logs describe-log-groups `
--log-group-name-prefix /aws/lambda/everyonecook-dev `
--query 'logGroups[].logGroupName'
# Get API URL from CloudFormation
$apiUrl = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Backend `
--query 'Stacks[0].Outputs[?OutputKey==`ApiCustomDomain`].OutputValue' `
--output text
Write-Host "API Endpoint: $apiUrl"
# Output: https://api-dev.everyonecook.cloud
# Test via API Gateway (real endpoint)
$response = Invoke-RestMethod -Uri "$apiUrl/health" -Method Get
$response | ConvertTo-Json
# Expected:
# {
# "status": "healthy",
# "timestamp": "2025-12-09T...",
# "service": "EveryoneCook API",
# "environment": "dev"
# }
# Get API ID
$apiId = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Backend `
--query 'Stacks[0].Outputs[?OutputKey==`ApiId`].OutputValue' `
--output text
# List deployments
aws apigateway get-deployments --rest-api-id $apiId
# Get latest deployment
aws apigateway get-deployment `
--rest-api-id $apiId `
--deployment-id (aws apigateway get-deployments `
--rest-api-id $apiId `
--query 'items[0].id' `
--output text)
Cognito triggers đã được deploy với Auth Stack. Verify:
# List Cognito User Pool triggers
$userPoolId = aws cloudformation describe-stacks `
--stack-name EveryoneCook-dev-Auth `
--query 'Stacks[0].Outputs[?OutputKey==`UserPoolId`].OutputValue' `
--output text
aws cognito-idp describe-user-pool `
--user-pool-id $userPoolId `
--query 'UserPool.LambdaConfig'
# Expected:
# {
# "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"
# }
# Get AI Worker function
aws lambda get-function --function-name everyonecook-dev-ai-worker
# Check event source mapping (SQS trigger)
aws lambda list-event-source-mappings `
--function-name everyonecook-dev-ai-worker
# Expected: Event source từ AI Queue
# Get AI Queue URL
$queueUrl = aws sqs list-queues `
--queue-name-prefix everyonecook-dev-ai-queue `
--query 'QueueUrls[0]' `
--output text
# Send test message
aws sqs send-message `
--queue-url $queueUrl `
--message-body '{"type":"test","data":"worker-verification"}'
# Check worker logs
aws logs tail /aws/lambda/everyonecook-dev-ai-worker --follow
Sử dụng checklist này để verify deployment:
All 7 Lambda functions deployed
Runtime: nodejs20.x
Handler paths correct
Timeout: 30 seconds
Memory: 512 MB (auth, social), 1024 MB (ai)
Lambda Layer attached to all functions
Environment variables configured correctly
Code SHA256 changed (code updated)
api-dev.everyonecook.cloudGET /health# Check TypeScript errors
cd services/auth-module
npx tsc --noEmit
# Fix errors và rebuild
npm run build
# Check for node_modules in dist
Get-ChildItem -Path services/*/dist/node_modules -Recurse
# Script sẽ auto-remove, hoặc manual:
Remove-Item services/auth-module/dist/node_modules -Recurse -Force
# Rebuild
cd services/auth-module
npm run build
# Check function state
aws lambda get-function `
--function-name everyonecook-dev-auth-user `
--query 'Configuration.{State:State,StateReason:StateReason}'
# If state is "Failed", check logs
aws logs tail /aws/lambda/everyonecook-dev-auth-user --since 10m
# Increase timeout (via CDK hoặc AWS CLI)
aws lambda update-function-configuration `
--function-name everyonecook-dev-auth-user `
--timeout 60
# Hoặc update trong backend-stack.ts và redeploy
# Increase memory
aws lambda update-function-configuration `
--function-name everyonecook-dev-recipe-ai `
--memory-size 1024
# AI functions cần 1024 MB cho Bedrock calls
# Get layer ARN
$layerArn = aws lambda list-layer-versions `
--layer-name everyonecook-shared-deps-dev `
--query 'LayerVersions[0].LayerVersionArn' `
--output text
# Attach layer manually
aws lambda update-function-configuration `
--function-name everyonecook-dev-auth-user `
--layers $layerArn
# Check current env vars
aws lambda get-function-configuration `
--function-name everyonecook-dev-auth-user `
--query 'Environment.Variables'
# Update manually (hoặc via CDK)
aws lambda update-function-configuration `
--function-name everyonecook-dev-auth-user `
--environment "Variables={TABLE_NAME=EveryoneCook-dev,REGION=ap-southeast-1}"
# Get invocation count (last 1 hour)
$startTime = (Get-Date).AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ss")
$endTime = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss")
aws cloudwatch get-metric-statistics `
--namespace AWS/Lambda `
--metric-name Invocations `
--dimensions Name=FunctionName,Value=everyonecook-dev-api-router `
--start-time $startTime `
--end-time $endTime `
--period 300 `
--statistics Sum
# Get error count
aws cloudwatch get-metric-statistics `
--namespace AWS/Lambda `
--metric-name Errors `
--dimensions Name=FunctionName,Value=everyonecook-dev-api-router `
--start-time $startTime `
--end-time $endTime `
--period 300 `
--statistics Sum
# Get average duration
aws cloudwatch get-metric-statistics `
--namespace AWS/Lambda `
--metric-name Duration `
--dimensions Name=FunctionName,Value=everyonecook-dev-api-router `
--start-time $startTime `
--end-time $endTime `
--period 300 `
--statistics Average,Maximum
# Check concurrent executions
aws cloudwatch get-metric-statistics `
--namespace AWS/Lambda `
--metric-name ConcurrentExecutions `
--dimensions Name=FunctionName,Value=everyonecook-dev-api-router `
--start-time $startTime `
--end-time $endTime `
--period 300 `
--statistics Maximum
Development:
# Fast iteration - Lambda Only
.\deploy\deploy-backend.ps1 -LambdaOnly
Staging/Production:
# Full deployment with CDK
.\deploy\deploy-backend.ps1 -Environment prod
# Verify thoroughly before proceeding
# Get previous version
aws lambda list-versions-by-function `
--function-name everyonecook-dev-auth-user
# Rollback to version X
aws lambda update-alias `
--function-name everyonecook-dev-auth-user `
--name LIVE `
--function-version X
# Deploy to new version
.\deploy\deploy-backend.ps1 -Environment dev
# Test new version
# If OK, traffic shift complete
# If issues, rollback alias
# Create CloudWatch alarm for errors
aws cloudwatch put-metric-alarm `
--alarm-name everyonecook-dev-api-router-errors `
--alarm-description "Alert on Lambda errors" `
--metric-name Errors `
--namespace AWS/Lambda `
--statistic Sum `
--period 300 `
--evaluation-periods 1 `
--threshold 10 `
--comparison-operator GreaterThanThreshold `
--dimensions Name=FunctionName,Value=everyonecook-dev-api-router
Expected Deployment Times:
| Operation | Time | Notes |
|---|---|---|
| Build Layer | 30-60s | npm install production deps |
| Build Modules | 20-40s | TypeScript compilation (7 modules) |
| Validate & Package | 10-20s | ZIP creation |
| CDK Deploy | 3-5 min | CloudFormation update |
| Lambda Only | 1-2 min | Direct function update |
Expected Lambda Performance:
| Function | Cold Start | Warm | Memory | Timeout |
|---|---|---|---|---|
| api-router | 800-1200ms | 50-100ms | 512 MB | 30s |
| auth-user | 600-900ms | 80-150ms | 512 MB | 30s |
| social | 700-1000ms | 100-200ms | 512 MB | 30s |
| recipe-ai | 1500-2500ms | 200-500ms | 1024 MB | 60s |
| ai-worker | 2000-3000ms | 300-800ms | 1024 MB | 300s |
| admin | 600-800ms | 100-150ms | 512 MB | 30s |
| upload | 400-600ms | 50-80ms | 256 MB | 15s |
Để tự động hóa deployment trong GitLab CI/CD:
# .gitlab-ci.yml
deploy-backend:
stage: deploy
script:
- cd everyonecook
- .\deploy\deploy-backend.ps1 -Environment $CI_ENVIRONMENT_NAME -LambdaOnly
only:
- main
environment:
name: production
Trong lab này, bạn đã:
✅ Deploy Lambda Functions: 7 modules + 5 Cognito triggers
✅ Deploy Lambda Layer: Shared dependencies
✅ Configure API Gateway: Custom domain integration
✅ Setup SQS Workers: Async processing
✅ Verify Deployment: Health checks, logs, metrics
✅ Performance Tuning: Warm up functions, optimize cold start
Key Achievements:
Backend đã deployed thành công! Tiếp theo:
Proceed to: 5.08 - Test Endpoints End-to-End
# Test get posts
aws lambda invoke \
--function-name EveryoneCook-dev-SocialModule \
--payload '{
"httpMethod":"GET",
"path":"/social/posts",
"headers":{"Authorization":"Bearer test-token"},
"requestContext":{"authorizer":{"claims":{"sub":"test-user-id","username":"testuser"}}}
}' \
response.json
cat response.json
1. View Recent Logs
# Tail Auth Module logs
aws logs tail /aws/lambda/EveryoneCook-dev-AuthModule --follow
# Or view last 10 minutes
aws logs tail /aws/lambda/EveryoneCook-dev-AuthModule --since 10m
2. Search for Errors
# Search for errors in last hour
aws logs filter-log-events \
--log-group-name /aws/lambda/EveryoneCook-dev-AuthModule \
--start-time $(date -d '1 hour ago' +%s)000 \
--filter-pattern "ERROR"
3. Check Lambda Insights
# Get Lambda metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Invocations \
--dimensions Name=FunctionName,Value=EveryoneCook-dev-AuthModule \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Sum
Screenshot: CloudWatch Logs showing Lambda execution
Lambda triggers đã được deploy với Auth Stack, verify:
# Check Post-Confirmation trigger
aws lambda get-function \
--function-name EveryoneCook-dev-PostConfirmationTrigger
# Test trigger (will be invoked automatically on user confirmation)
1. Deploy Worker
# Worker được deploy với Backend Stack
# Verify deployment
aws lambda get-function \
--function-name EveryoneCook-dev-SearchSyncWorker
2. Test Worker with SQS
# Get SearchIndex queue URL
QUEUE_URL=$(aws sqs list-queues \
--queue-name-prefix EveryoneCook-dev-SearchIndexQueue \
| jq -r '.QueueUrls[0]')
# Send test message
aws sqs send-message \
--queue-url $QUEUE_URL \
--message-body '{
"eventName": "INSERT",
"tableName": "recipes",
"keys": {"PK": "USER#testuser", "SK": "RECIPE#test-123"},
"newImage": {"title": "Test Recipe", "cuisine": "Vietnamese"}
}'
# Check worker logs
aws logs tail /aws/lambda/EveryoneCook-dev-SearchSyncWorker --follow
API Gateway tự động update khi deploy Backend Stack, verify:
# Get API Gateway deployment
API_ID=$(aws cloudformation describe-stacks \
--stack-name EveryoneCook-dev-Backend \
--query 'Stacks[0].Outputs[?OutputKey==`ApiId`].OutputValue' \
--output text)
# List deployments
aws apigateway get-deployments --rest-api-id $API_ID
# Get latest deployment
aws apigateway get-deployment \
--rest-api-id $API_ID \
--deployment-id $(aws apigateway get-deployments \
--rest-api-id $API_ID \
--query 'items[0].id' \
--output text)
Tránh cold start cho requests đầu tiên:
# Invoke all functions once
for func in APIRouter AuthModule SocialModule RecipeAIModule AdminModule UploadModule SearchSyncWorker; do
echo "Warming up $func..."
aws lambda invoke \
--function-name EveryoneCook-dev-$func \
--payload '{"warmup":true}' \
/dev/null
done
1. Test Health Endpoint
# Test via API Gateway
curl https://api.everyonecook.cloud/health
# Should return: {"status":"healthy","timestamp":"..."}
2. Test with Postman
Import Postman collection:
{
"info": {
"name": "EveryoneCook API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Health Check",
"request": {
"method": "GET",
"url": "https://api.everyonecook.cloud/health"
}
}
]
}
Issue: Lambda update fails
# Check function state
aws lambda get-function \
--function-name EveryoneCook-dev-AuthModule \
--query 'Configuration.State'
# If state is "Failed", check StateReasonCode
aws lambda get-function \
--function-name EveryoneCook-dev-AuthModule \
--query 'Configuration.StateReasonCode'
Issue: Function timeout
# Increase timeout
aws lambda update-function-configuration \
--function-name EveryoneCook-dev-AuthModule \
--timeout 30
Issue: Out of memory
# Increase memory
aws lambda update-function-configuration \
--function-name EveryoneCook-dev-AuthModule \
--memory-size 512
Issue: Environment variables missing
# Update environment variables
aws lambda update-function-configuration \
--function-name EveryoneCook-dev-AuthModule \
--environment Variables={TABLE_NAME=EveryoneCook-dev,REGION=us-east-1}
Check Lambda metrics:
# Invocations
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Invocations \
--dimensions Name=FunctionName,Value=EveryoneCook-dev-AuthModule \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Sum
# Errors
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Errors \
--dimensions Name=FunctionName,Value=EveryoneCook-dev-AuthModule \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Sum
# Duration
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Duration \
--dimensions Name=FunctionName,Value=EveryoneCook-dev-AuthModule \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Average,Maximum
Once backend is deployed and verified, proceed to Test Endpoints End-to-End to test the complete application flow.