Tuần 1 - Ngày 5: Amazon ECR và Deploy lên ECS Fargate
Mục tiêu học tập
- Tạo ECR repository và push Docker image từ local
- Hiểu authentication flow ECR (
aws ecr get-login-password) - Viết ECS Task Definition và tạo ECS Service trên Fargate
- Hiểu sự khác biệt giữa ECS launch type EC2 vs Fargate
- Nắm sơ lược ECS vs EKS khi nào dùng cái nào
1. Amazon ECR — Container Registry
Tại sao cần private registry?
Docker Hub public registry tiện cho open-source image nhưng không phù hợp cho production app vì:
- Rate limiting trên free tier (100 pull/6h với IP chia sẻ)
- Image public → ai cũng pull được
- Không tích hợp sẵn với IAM policy
Amazon ECR giải quyết tất cả và tích hợp sâu với ECS/EKS/Fargate.
Tạo ECR repository
# Tạo repository
aws ecr create-repository \
--repository-name myapp \
--region ap-southeast-1 \
--image-scanning-configuration scanOnPush=true \
--encryption-configuration encryptionType=AES256
# Output:
# {
# "repository": {
# "repositoryArn": "arn:aws:ecr:ap-southeast-1:123456789012:repository/myapp",
# "registryId": "123456789012",
# "repositoryName": "myapp",
# "repositoryUri": "123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/myapp",
# ...
# }
# }
Authentication — quan trọng nhất
# ECR dùng token tạm thời (12 giờ), không phải username/password cố định
# Lấy token và pipe vào docker login
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
AWS_REGION=ap-southeast-1
aws ecr get-login-password --region ${AWS_REGION} | \
docker login \
--username AWS \
--password-stdin \
${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
# Output: Login Succeeded
Điểm quan trọng: Username LUÔN là
AWS(chữ hoa). Password là token tạm thời từget-login-password. Không bao giờ hard-code credentials trong Dockerfile hay docker-compose.
Tag và Push image
# Build image (hoặc dùng image đã build)
docker build -t myapp:1.0 .
# Tag với ECR URI
REPO_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/myapp"
docker tag myapp:1.0 ${REPO_URI}:1.0
docker tag myapp:1.0 ${REPO_URI}:latest
# Push lên ECR
docker push ${REPO_URI}:1.0
docker push ${REPO_URI}:latest
# Kiểm tra image đã push
aws ecr list-images --repository-name myapp --region ${AWS_REGION}
ECR Lifecycle Policy — tự động dọn image cũ
{
"rules": [
{
"rulePriority": 1,
"description": "Giữ tối đa 10 image có tag",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Xoá untagged image sau 7 ngày",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
}
]
}
2. Amazon ECS — Kiến trúc tổng quan
Các khái niệm ECS
| Khái niệm | Mô tả |
|---|---|
| Cluster | Logical grouping của tasks/services |
| Task Definition | Blueprint mô tả container(s): image, CPU, memory, env vars, ports |
| Task | Một instance đang chạy của Task Definition |
| Service | Đảm bảo N tasks luôn chạy, tích hợp với ALB, rolling update |
| Launch Type | EC2 (bạn manage) hoặc Fargate (AWS manage) |
3. ECS Launch Type: EC2 vs Fargate
| Tiêu chí | EC2 Launch Type | Fargate |
|---|---|---|
| Quản lý server | Bạn (patch OS, scale) | AWS (fully managed) |
| Cost | EC2 instance giờ (có thể dùng Reserved/Spot) | Theo vCPU/GB-giờ của task |
| Burst flexibility | Cần scale cluster trước | Scale ngay, không cần cluster capacity |
| GPU | Có (EC2 GPU instance) | Không (tính đến 2024) |
| Windows containers | Có | Có |
| Spot tasks | Có (EC2 Spot) | Có (Fargate Spot — ~70% rẻ hơn) |
| Best for | Large steady workload, cần GPU | Variable load, microservices |
4. Tạo ECS Fargate Service (CLI)
Bước 1: Tạo Task Definition
# task-definition.json
cat > task-definition.json << 'EOF'
{
"family": "myapp",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "myapp",
"image": "123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/myapp:1.0",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{ "name": "NODE_ENV", "value": "production" }
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:ap-southeast-1:123456789012:secret:myapp/db-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3
}
}
]
}
EOF
# Register task definition
aws ecs register-task-definition \
--cli-input-json file://task-definition.json \
--region ap-southeast-1
Bước 2: Tạo CloudWatch Log Group
aws logs create-log-group \
--log-group-name /ecs/myapp \
--region ap-southeast-1
Bước 3: Tạo ECS Cluster
aws ecs create-cluster \
--cluster-name myapp-cluster \
--region ap-southeast-1
Bước 4: Tạo ECS Service
aws ecs create-service \
--cluster myapp-cluster \
--service-name myapp-service \
--task-definition myapp:1 \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-abc123,subnet-def456],
securityGroups=[sg-xyz789],
assignPublicIp=ENABLED
}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,
containerName=myapp,containerPort=3000" \
--region ap-southeast-1
IAM Roles cần thiết
ecsTaskExecutionRole — cho ECS agent:
- ecr:GetAuthorizationToken ← pull image từ ECR
- ecr:BatchGetImage
- ecr:GetDownloadUrlForLayer
- logs:CreateLogStream ← ghi CloudWatch Logs
- logs:PutLogEvents
- secretsmanager:GetSecretValue ← lấy secrets
ecsTaskRole — cho app code trong container:
- Quyền app cần (S3, DynamoDB, v.v.) — tùy ứng dụng
5. Update service — Rolling deployment
# 1. Push image mới lên ECR
docker build -t myapp:1.1 .
docker tag myapp:1.1 ${REPO_URI}:1.1
docker push ${REPO_URI}:1.1
# 2. Đăng ký task definition mới (thay image tag)
# Sửa task-definition.json: image → myapp:1.1
aws ecs register-task-definition \
--cli-input-json file://task-definition.json
# 3. Update service — ECS sẽ rolling deploy
aws ecs update-service \
--cluster myapp-cluster \
--service myapp-service \
--task-definition myapp:2 \ # revision mới
--region ap-southeast-1
# 4. Theo dõi deployment
aws ecs describe-services \
--cluster myapp-cluster \
--services myapp-service \
--query 'services[0].deployments'
6. ECS vs EKS — khi nào chọn gì?
Khi chọn ECS: team nhỏ, không có Kubernetes expertise, AWS-only, budget tight.
Khi chọn EKS: team đã có Kubernetes knowledge, cần Helm/service mesh, multi-cloud strategy, cần advanced autoscaling (KEDA, Karpenter).
Câu hỏi ôn tập
-
Username trong lệnh
docker logincho ECR luôn là gì?Xem đáp án
Luôn là
AWS(viết hoa). Password là token tạm thời lấy từaws ecr get-login-password. Lệnh đầy đủ:aws ecr get-login-password --region ... | docker login --username AWS --password-stdin <registry-uri>. Token này có hiệu lực 12 giờ. -
Tại sao phải dùng
aws ecr get-login-passwordthay vì username/password cố định?Xem đáp án
ECR không có username/password cố định. Thay vào đó, authentication dựa trên IAM — token được sinh ra từ credentials IAM hiện tại và có hiệu lực 12 giờ. Điều này đảm bảo: (1) không cần quản lý static credentials cho registry, (2) access bị kiểm soát bởi IAM policies, (3) token tự hết hạn giảm rủi ro nếu bị lộ.
-
Sự khác biệt giữa
ecsTaskExecutionRolevàecsTaskRolelà gì?Xem đáp án
ecsTaskExecutionRoledùng cho ECS agent (không phải app): cần để pull image từ ECR, ghi logs vào CloudWatch, và lấy secrets từ Secrets Manager khi khởi động task.ecsTaskRoledùng cho code trong container: các AWS API calls mà app cần (S3, DynamoDB, SQS...) trong lúc chạy. Hai role có trách nhiệm tách biệt rõ ràng theo least privilege. -
Fargate Spot tiết kiệm được bao nhiêu % so với Fargate on-demand?
Xem đáp án
Fargate Spot tiết kiệm khoảng ~70% so với Fargate on-demand. AWS có thể reclaim capacity khi cần, nên Fargate Spot phù hợp cho workload fault-tolerant như batch jobs, data processing, CI/CD tasks — không phù hợp cho production web server yêu cầu availability cao.
-
Tại sao ECS Task Definition cần
networkMode: awsvpckhi dùng Fargate?Xem đáp án
Fargate chỉ hỗ trợ
awsvpcnetwork mode. Mỗi Fargate task được cấp một ENI (Elastic Network Interface) riêng với IP private trong VPC — giống như một EC2 instance. Điều này cho phép gắn Security Group trực tiếp vào task (không phải instance), kiểm soát traffic ở task level, và tích hợp với VPC networking (subnets, route tables, VPC endpoints).
Bài tập thực hành
# Prerequisites: AWS CLI đã configure, có quyền ECR + ECS
# 1. Tạo ECR repo
AWS_REGION=ap-southeast-1
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REPO_NAME=my-docker-demo
aws ecr create-repository \
--repository-name ${REPO_NAME} \
--region ${AWS_REGION}
# 2. Auth vào ECR
aws ecr get-login-password --region ${AWS_REGION} | \
docker login --username AWS --password-stdin \
${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
# 3. Build và push image
docker build -t ${REPO_NAME}:latest .
docker tag ${REPO_NAME}:latest \
${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${REPO_NAME}:latest
docker push \
${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${REPO_NAME}:latest
# 4. Kiểm tra
aws ecr describe-images \
--repository-name ${REPO_NAME} \
--region ${AWS_REGION}
# 5. (Optional) Xoá repo sau khi thực hành
aws ecr delete-repository \
--repository-name ${REPO_NAME} \
--force \
--region ${AWS_REGION}
Tài liệu tham khảo chính thức
- Amazon ECR user guide
- Amazon ECS developer guide
- AWS Fargate developer guide
- ECS vs EKS decision guide
- ECS task execution IAM role
Tiếp theo: Ngày 6 — Security và Image Optimization