🎯 Mục tiêu Task 11: Thiết lập pipeline CI/CD cho backend NestJS monolithic: GitHub → Build → ECR → Deploy ECS
🔐 Security Best Practice: Trong production environment, nên tạo custom policies với principle of least privilege thay vì sử dụng managed policies có quyền rộng như FullAccess
📋 Prerequisites: Cần hoàn thành Task 8 (ECR), Task 9 (ECS Fargate) trước khi bắt đầu CI/CD setup.
AWS Console → S3:
vinashoes-artifacts-prod
📝 CLI Alternative:
# Tạo S3 bucket bằng AWS CLI
aws s3api create-bucket \
--bucket vinashoes-artifacts-prod \
--region ap-southeast-1 \
--create-bucket-configuration LocationConstraint=ap-southeast-1
# Enable versioning
aws s3api put-bucket-versioning \
--bucket vinashoes-artifacts-prod \
--versioning-configuration Status=Enabled
🔐 Lưu ý Bảo mật:
📝 CLI Reference:
# Set bucket encryption
aws s3api put-bucket-encryption \
--bucket vinashoes-artifacts-prod \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# Verify bucket settings
aws s3api get-bucket-location --bucket vinashoes-artifacts-prod
aws s3api get-bucket-versioning --bucket vinashoes-artifacts-prod
💡 S3 Optimization: Enable S3 Intelligent Tiering để tự động optimize storage costs cho artifacts.
AWS Console → IAM → Roles:
🎯 Mục đích IAM Role:
AWSCodeBuildDeveloperAccessAmazonEC2ContainerRegistryPowerUserAmazonS3FullAccess
VinaShoesCodeBuildRoleRole for CodeBuild to build Docker images and push to ECR
📝 CLI Alternative - Create CodeBuild Role:
# Tạo trust policy file
cat > codebuild-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codebuild.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# Tạo role
aws iam create-role \
--role-name VinaShoesCodeBuildRole \
--assume-role-policy-document file://codebuild-trust-policy.json
# Attach policies
aws iam attach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess
aws iam attach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
aws iam attach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
T?o Role:
Select Service:
Add Permissions:
AWSCodePipelineFullAccessAmazonECS_FullAccessAmazonS3FullAccessAWSCodeBuildDeveloperAccess📝 Lưu ý: Nếu không tìm thấy AWSCodePipelineFullAccess, có thể sử dụng:
AWSCodePipelineCustomActionAccessAWSCodePipelineApproverAccessHoặc tạo Custom Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codepipeline:*",
"codebuild:BatchGetBuilds",
"codebuild:StartBuild",
"ecs:UpdateService",
"ecs:DescribeServices",
"ecs:DescribeTaskDefinition",
"ecs:DescribeTasks",
"ecs:ListTasks",
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": "*"
}
]
}
VinaShoesCodePipelineCustomPolicy
VinaShoesCodePipelineRoleRole for CodePipeline to orchestrate CI/CD workflow
VinaShoesCodePipelineCustomPolicy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
� CLI Alternative - Create CodePipeline Role:
# Tạo trust policy file
cat > codepipeline-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# Tạo custom policy
cat > codepipeline-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codepipeline:*",
"codebuild:BatchGetBuilds",
"codebuild:StartBuild",
"ecs:UpdateService",
"ecs:DescribeServices",
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": "*"
}
]
}
EOF
# Tạo role và policy
aws iam create-policy \
--policy-name VinaShoesCodePipelineCustomPolicy \
--policy-document file://codepipeline-policy.json
aws iam create-role \
--role-name VinaShoesCodePipelineRole \
--assume-role-policy-document file://codepipeline-trust-policy.json
# Attach policy
aws iam attach-role-policy \
--role-name VinaShoesCodePipelineRole \
--policy-arn arn:aws:iam::577638368374:policy/VinaShoesCodePipelineCustomPolicy
�🔍 Verify Roles Created:
VinaShoes để xem 2 roles đã tạo🔐 Security Best Practice: Trong production environment, nên tạo custom policies với principle of least privilege thay vì sử dụng managed policies có quyền rộng như FullAccess.
AWS Console → Developer Tools → CodeBuild → Build projects → Create build project:
vinashoes-backend-buildBuild NestJS backend to Docker image
🏗️ CodeBuild Project Naming:
<service>-<environment>-build
https://github.com/your-username/vinashoes-backendmain📝 GitHub Integration Best Practices:
repo scope cho private repositoriesCLI Reference - Test GitHub Connection:
# Test repository access (cần GitHub CLI)
gh repo view uit-ntn/vina-shoes-server
# Clone repository locally để test
git clone https://github.com/uit-ntn/vina-shoes-server.git
Provisioning Model:
Environment Image:
Compute:
Running Mode:
Operating System:
Runtime(s):
Image:
Image Version:
🖥️ Compute Environment Options:
Container Runtime:
VinaShoesCodeBuildRole from dropdown🔧 Privileged Mode: Cần enable privileged mode cho Docker builds. Điều này sẽ được config trong Additional configuration section.
⚠️ Security Implications:
📝 CLI Alternative - Create CodeBuild Project:
# Tạo build project specification
cat > codebuild-project.json << EOF
{
"name": "vinashoes-backend-build",
"description": "Build NestJS backend to Docker image",
"source": {
"type": "GITHUB",
"location": "https://github.com/uit-ntn/vina-shoes-server.git"
},
"artifacts": {
"type": "NO_ARTIFACTS"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
"computeType": "BUILD_GENERAL1_MEDIUM",
"privilegedMode": true
},
"serviceRole": "arn:aws:iam::577638368374:role/VinaShoesCodeBuildRole"
}
EOF
# Tạo project
aws codebuild create-project --cli-input-json file://codebuild-project.json
Build Specifications:
Option 1: Use a buildspec file (Recommended)
buildspec.yml (hoặc để trống để dùng default)Option 2: Insert build commands
# Build commands cho NestJS Docker build
echo "=== Pre-build phase ==="
echo "Logging in to Amazon ECR..."
aws ecr get-login-password --region ap-southeast-1 | docker login --username AWS --password-stdin 577638368374.dkr.ecr.ap-southeast-1.amazonaws.com
echo "=== Build phase ==="
echo "Build started on $(date)"
echo "Building the Docker image..."
docker build -t vinashoes/backend-service:latest .
docker tag vinashoes/backend-service:latest 577638368374.dkr.ecr.ap-southeast-1.amazonaws.com/vinashoes/backend-service:latest
echo "=== Post-build phase ==="
echo "Build completed on $(date)"
echo "Pushing the Docker images..."
docker push 577638368374.dkr.ecr.ap-southeast-1.amazonaws.com/vinashoes/backend-service:latest
echo "Writing image definitions file..."
printf '[{"name":"backend-container","imageUri":"%s"}]' 577638368374.dkr.ecr.ap-southeast-1.amazonaws.com/vinashoes/backend-service:latest > imagedefinitions.json
Username: AWS (cố định, luôn là “AWS” cho ECR)
Password: Được generate tự động bởi command aws ecr get-login-password
aws ecr get-login-password --region ap-southeast-1 → Generate temporary password| docker login --username AWS --password-stdin → Dùng password từ step 1Điều kiện:
ecr:GetAuthorizationToken📝 CLI Reference - ECR Commands:
# Get ECR login token
aws ecr get-login-password --region ap-southeast-1
# Login to ECR
aws ecr get-login-password --region ap-southeast-1 | \
docker login --username AWS --password-stdin \
577638368374.dkr.ecr.ap-southeast-1.amazonaws.com
# List ECR repositories
aws ecr describe-repositories --region ap-southeast-1
# Create ECR repository if not exists
aws ecr create-repository \
--repository-name vinashoes/backend-service \
--region ap-southeast-1
📋 Cách paste commands vào CodeBuild:
echo "=== Pre-build phase ===" đến cuối)
📝 Environment Variables cần thiết:
AWS_ACCOUNT_ID: 577638368374IMAGE_TAG: latest hoặc commit hash🔧 Advanced Environment Variables:
AWS_DEFAULT_REGION=ap-southeast-1
AWS_ACCOUNT_ID=577638368374
IMAGE_REPO_NAME=vinashoes/backend-service
IMAGE_TAG=latest
DOCKER_BUILDKIT=1 # Enable Docker BuildKit for faster builds
⚠️ Source Warning: Nếu primary source là “No source”, cần cung cấp valid buildspec command. Đảm bảo đã config GitHub source ở bước trước.
🚨 Common BuildSpec Errors:
docker login command → ECR authentication fails
💡 Why No Artifacts: Vì chúng ta push Docker image lên ECR, không cần store artifacts trong S3. ECS sẽ pull image trực tiếp từ ECR.
📋 Artifact Types Explained:
🚀 Performance Optimization - Caching:
# Trong buildspec.yml, thêm cache configuration
cache:
paths:
- '/root/.npm/**/*' # npm cache
- '/root/.cache/yarn/**/*' # yarn cache
- 'node_modules/**/*' # dependencies
- '/var/lib/docker/**/*' # Docker layer cache (nếu sử dụng)
📝 CLI - Enable Build Cache:
aws codebuild update-project \
--name vinashoes-backend-build \
--cache '{
"type": "S3",
"location": "vinashoes-artifacts-prod/build-cache"
}'
CloudWatch Logs:
/aws/codebuild/<project-name>)S3 Logs:
📊 Logging Best Practices:
📝 CLI - Configure Logging:
# Create CloudWatch log group
aws logs create-log-group \
--log-group-name /aws/codebuild/vinashoes-backend-build
# Set retention period (30 days)
aws logs put-retention-policy \
--log-group-name /aws/codebuild/vinashoes-backend-build \
--retention-in-days 30
vinashoes-backend-build� CLI - Start Build Test:
# Start a build manually
aws codebuild start-build \
--project-name vinashoes-backend-build
# Get build status
aws codebuild batch-get-builds \
--ids "build-id-from-previous-command"
# List recent builds
aws codebuild list-builds-for-project \
--project-name vinashoes-backend-build \
--sort-order DESCENDING
�🔧 Privileged Mode Required: Sau khi tạo project, cần enable Privileged mode:
Tạo file buildspec.yml trong root của backend repository:
version: 0.2
env:
variables:
AWS_DEFAULT_REGION: ap-southeast-1
AWS_ACCOUNT_ID: "577638368374"
IMAGE_REPO_NAME: vinashoes/backend-service
IMAGE_TAG: latest
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
- REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $REPOSITORY_URI:$IMAGE_TAG
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $REPOSITORY_URI:latest
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $REPOSITORY_URI:$IMAGE_TAG
- docker push $REPOSITORY_URI:latest
- echo Writing image definitions file...
- printf '[{"name":"backend-container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
- '**/*'
💡 BuildSpec Best Practices:
577638368374🚀 Advanced BuildSpec Features:
# Multi-stage builds với cache
pre_build:
commands:
- echo Build cache warming...
- docker pull $REPOSITORY_URI:latest || true
build:
commands:
- docker build --cache-from $REPOSITORY_URI:latest -t $IMAGE_REPO_NAME:$IMAGE_TAG .
# Testing phase
post_build:
commands:
- echo Running tests...
- docker run --rm $IMAGE_REPO_NAME:$IMAGE_TAG npm test
- echo Pushing only if tests pass...
- docker push $REPOSITORY_URI:$IMAGE_TAG
📝 CLI - Validate BuildSpec:
# Validate buildspec syntax
aws codebuild validate-project \
--source '{
"type": "GITHUB",
"location": "https://github.com/uit-ntn/vina-shoes-server.git",
"buildspec": "buildspec.yml"
}'
🔧 Required Configuration: Sau khi tạo project, cần enable Privileged mode trong Environment settings:
AWS Console → CodePipeline → Create pipeline:
💡 Template Benefits:
🔄 Template vs Manual Setup:
📋 Available Templates:
Source Configuration:
Repository Details:
uit-ntn/vina-shoes-servermain
🔗 GitHub Connection Types:
📝 CLI - List CodeStar Connections:
# List existing connections
aws codestar-connections list-connections
# Get connection details
aws codestar-connections get-connection \
--connection-arn "arn:aws:codestar-connections:region:account:connection/connection-id"
Template sẽ tự động điền một số thông tin từ các bước trước:
Template Details (Read-only):
uit-ntn/vina-shoes-servermainPipeline Configuration (Editable):
CodePipelineName:
SimpleDockerService thành: vinashoes-backend-pipelineDockerBuildContext:
. (build từ root directory)DockerFilePath:
./DockerfileImageTag:
latestRetentionPolicy:
🏗️ Template Configuration Explained:
${CODEBUILD_BUILD_NUMBER}🔧 Advanced Configuration Options:
# Có thể sử dụng trong template parameters
DockerBuildArgs: |
--build-arg NODE_ENV=production
--build-arg API_VERSION=v1
ImageTag: "${CODEBUILD_BUILD_NUMBER}-${CODEBUILD_RESOLVED_SOURCE_VERSION}"
Template “Push to ECR” sẽ tự động tạo:
💡 Template Workflow: Template “Push to ECR” tạo 2-stage pipeline:
Khác với manual setup: Template không bao gồm deploy stage. Sau khi pipeline chạy thành công, bạn cần manually update ECS service để sử dụng image mới từ ECR.
🔄 ECS Deployment: Template này chỉ build và push image lên ECR. Để tự động deploy lên ECS, bạn cần:
📝 CLI - Add ECS Deploy Stage:
# Get current pipeline definition
aws codepipeline get-pipeline \
--name vinashoes-backend-pipeline > pipeline.json
# Edit pipeline.json to add deploy stage, then update
aws codepipeline update-pipeline \
--cli-input-json file://pipeline.json
# Alternative: Use ECS rolling update
aws ecs update-service \
--cluster vinashoes-cluster \
--service vinashoes-backend \
--force-new-deployment
vinashoes-backend-pipeline
📝 CLI - Monitor CloudFormation:
# List stacks with pipeline name
aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE \
--query 'StackSummaries[?contains(StackName, `vinashoes-backend-pipeline`)]'
# Get stack details
aws cloudformation describe-stacks \
--stack-name "stack-name-from-above"
# List stack resources
aws cloudformation list-stack-resources \
--stack-name "stack-name-from-above"
vinashoes-backend-pipeline exists
📝 CLI - Verify Pipeline:
# Get pipeline details
aws codepipeline get-pipeline \
--name vinashoes-backend-pipeline
# List pipelines
aws codepipeline list-pipelines
# Get pipeline execution history
aws codepipeline list-pipeline-executions \
--pipeline-name vinashoes-backend-pipeline
📝 CLI - Verify Resources:
# List CodeBuild projects
aws codebuild list-projects
# Get project details
aws codebuild batch-get-projects \
--names "project-name-from-template"
# List ECR repositories
aws ecr describe-repositories
# Test ECR access
aws ecr get-login-password --region ap-southeast-1
# List S3 buckets created by template
aws s3 ls | grep -i pipeline
🏗️ Template Resources Created:
📋 Resource Naming Pattern:
vinashoes-backend-pipeline{pipeline-name}-{random-suffix}{pipeline-name} hoặc auto-generatedcodepipeline-{region}-{random-id}| Thành phần | Trạng thái | Chi tiết |
|---|---|---|
| ✅ S3 Artifacts | ACTIVE | vinashoes-artifacts-prod lưu trữ build logs |
| ✅ IAM Roles | CONFIGURED | CodeBuild + CodePipeline roles |
| ✅ CodeBuild | ACTIVE | Xây dựng & push Docker images |
| ✅ CodePipeline | ACTIVE | Pipeline automation 3 giai đoạn |
| ✅ ECS Integration | WORKING | Tự động deploy lên Fargate service |
🔄 Quy trình Triển khai Tự động:
Lợi ích đạt được:
Build Thất bại:
Deploy Thất bại:
Pipeline Stuck:
Hiệu suất:
Bảo mật:
Giám sát:
Xóa pipeline và tất cả associated resources:
# Delete CodePipeline
aws codepipeline delete-pipeline --name vinashoes-backend-pipeline
# Delete CloudFormation stack (nếu được tạo từ template)
aws cloudformation delete-stack --stack-name vinashoes-backend-pipeline
Xóa build project và associated resources:
# Delete CodeBuild project
aws codebuild delete-project --name vinashoes-backend-build
# Delete CloudWatch log group
aws logs delete-log-group --log-group-name "/aws/codebuild/vinashoes-backend-build"
Xóa container images và repository:
# Delete ECR repository (sẽ xóa tất cả images)
aws ecr delete-repository \
--repository-name vinashoes/backend-service \
--force
# Hoặc xóa từng image cụ thể
aws ecr batch-delete-image \
--repository-name vinashoes/backend-service \
--image-ids imageTag=latest
Xóa S3 bucket chứa build artifacts:
# Empty bucket trước khi xóa
aws s3 rm s3://vinashoes-artifacts-prod --recursive
# Delete bucket
aws s3 rb s3://vinashoes-artifacts-prod
Xóa service roles đã tạo:
# Detach policies trước khi xóa
aws iam detach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AWSCodeBuildDeveloperAccess
aws iam detach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
aws iam detach-role-policy \
--role-name VinaShoesCodeBuildRole \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# Xóa roles
aws iam delete-role --role-name VinaShoesCodeBuildRole
aws iam delete-role --role-name VinaShoesCodePipelineRole
Xóa log groups và metrics:
# Xóa CodeBuild log groups
aws logs delete-log-group --log-group-name "/aws/codebuild/vinashoes-backend-build"
# Xóa pipeline execution history (optional)
# Note: CloudWatch tự động xóa metrics sau 15 tháng
⚠️ Thứ Tự Dọn Dẹp CI/CD:
Cấu trúc giá AWS CI/CD:
| Thành Phần Dịch Vụ | Miễn Phí | Trả Phí | Ước Tính Chi Phí |
|---|---|---|---|
| CodePipeline | 1 pipeline free | $1/pipeline/tháng | $1/tháng |
| CodeBuild | 100 build minutes | $0.005/minute | $10-50/tháng |
| ECR Storage | 500MB free | $0.10/GB/tháng | $1-5/tháng |
| S3 Artifacts | 5GB free | $0.023/GB/tháng | $1-3/tháng |
| CloudWatch Logs | 5GB free | $0.50/GB ingested | $5-15/tháng |
Ước tính chi phí cho CI/CD pipeline:
Chi Phí Cơ Bản CI/CD:
CodePipeline: $1/tháng (1 pipeline)
CodeBuild: $25/tháng (500 build minutes)
ECR Storage: $2/tháng (20GB images)
S3 Artifacts: $1/tháng (50GB artifacts)
CloudWatch Logs: $8/tháng (16GB logs)
Build Frequency:
Daily builds: 30 builds/tháng
Average build time: 15 minutes
Peak usage: 1000 minutes/tháng
Tổng Chi Phí Hàng Tháng: $37/tháng
Giảm chi phí CI/CD:
Chiến Thuật Tối Ưu:
1. Build Optimization:
- Sử dụng build cache để giảm build time
- Implement parallel builds cho multiple services
- Optimize Docker layers để giảm image size
2. Storage Management:
- Set ECR lifecycle policies để xóa old images
- Configure S3 lifecycle cho artifacts
- Use CloudWatch log retention policies
3. Pipeline Efficiency:
- Combine multiple services vào single pipeline
- Use conditional builds để skip unnecessary steps
- Implement build queuing để optimize resource usage
Lợi Ích CI/CD Automation vs Chi Phí:
| Loại Lợi Ích | Giá Trị | Tác Động Chi Phí |
|---|---|---|
| Developer Productivity | Giảm 50% deployment time | $20K+ mỗi developer/năm |
| Deployment Frequency | Tăng từ weekly sang daily | $50K+ faster time-to-market |
| Error Reduction | Giảm 80% manual deployment errors | $10K+ fewer outages |
| Rollback Speed | Instant rollbacks vs hours | $100K+ business continuity |
| Quality Assurance | Automated testing integration | $30K+ improved quality |
Tính Toán ROI:
Theo dõi chi tiêu CI/CD:
# Kiểm tra chi phí CodeBuild
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--granularity MONTHLY \
--metrics BlendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--filter '{
"Dimensions": {
"Key": "SERVICE",
"Values": ["AWS CodeBuild"]
}
}'
# Giám sát build usage
aws codebuild list-builds \
--sort-order DESCENDING \
--query 'builds[*].{id:id,buildNumber:buildNumber,duration:duration,endTime:endTime}'
# Check ECR storage usage
aws ecr describe-repositories \
--query 'repositories[*].{repositoryName:repositoryName,imageCount:imageCount}'
# Monitor S3 artifact storage
aws s3 ls s3://vinashoes-artifacts-prod --recursive --summarize
💡 Thực Tiễn Quản Lý Chi Phí Tốt Nhất
Build Optimization:
Storage Management:
Cost Monitoring:
Scaling Considerations:
🚀 Production-Ready AWS Microservices Platform with Complete CI/CD! 🚀