Container trên AWS — Tổng quan
Container là đơn vị đóng gói ứng dụng cùng toàn bộ dependencies, cho phép chạy nhất quán trên mọi môi trường. AWS cung cấp ba dịch vụ chính để chạy container: Amazon ECS, Amazon EKS và AWS Fargate (serverless compute engine dùng chung cho cả ECS lẫn EKS).
So sánh ECS vs EKS vs Fargate
| Tiêu chí | Amazon ECS | Amazon EKS | AWS Fargate |
|---|---|---|---|
| Loại dịch vụ | Container orchestration (AWS native) | Managed Kubernetes | Serverless compute engine |
| Control Plane | AWS quản lý hoàn toàn, miễn phí | AWS quản lý, phí $0.10/giờ/cluster | Không có (dùng chung ECS/EKS) |
| Độ phức tạp | Thấp | Cao | Rất thấp |
| Portability | Lock-in AWS | Multi-cloud, on-prem (EKS Anywhere) | Lock-in AWS |
| Ecosystem | AWS native tools | Toàn bộ K8s ecosystem (Helm, Istio...) | Phụ thuộc ECS hoặc EKS |
| Pricing | Chỉ trả EC2/Fargate | $0.10/giờ + EC2/Fargate | Trả theo vCPU + memory/giây |
| Phù hợp khi | Team nhỏ, all-in AWS, muốn đơn giản | Đã dùng K8s, cần multi-cloud, ecosystem lớn | Không muốn quản lý server, workload biến động |
- Mới bắt đầu, team nhỏ: ECS + Fargate — đơn giản nhất, không cần quản lý server
- Đã có kinh nghiệm Kubernetes: EKS — tận dụng K8s ecosystem, dễ migrate
- Workload lớn, cần tối ưu chi phí: ECS/EKS + EC2 — kiểm soát instance type, Spot Instances
- Batch jobs, cron jobs: ECS + Fargate — chỉ trả tiền khi task chạy
- Multi-cloud strategy: EKS — Kubernetes chạy được ở mọi nơi
Sơ đồ tổng quan Container Services trên AWS
Amazon ECS — Kiến trúc
Amazon Elastic Container Service (ECS) là dịch vụ điều phối container được AWS quản lý hoàn toàn. ECS giúp bạn chạy, dừng và quản lý container trên một cluster mà không cần cài đặt hay vận hành phần mềm orchestration riêng.
Các thành phần chính
Sơ đồ kiến trúc ECS
- ECS Control Plane hoàn toàn miễn phí — bạn chỉ trả tiền cho compute (EC2 hoặc Fargate)
- Một Task Definition có thể chứa tối đa 10 container definitions
- Mỗi Task có một ENI riêng khi dùng
awsvpcnetwork mode - ECS Agent tự động cập nhật trên ECS-optimized AMI
ECS Launch Types — EC2 vs Fargate
Khi chạy task trên ECS, bạn chọn một trong hai launch type: EC2 (tự quản lý instance) hoặc Fargate (serverless). Mỗi loại có ưu nhược điểm riêng.
- Kiểm soát hoàn toàn instance type, AMI, storage
- Dùng được Spot Instances → tiết kiệm đến 90%
- GPU instances cho ML/AI workloads
- Placement strategies & constraints linh hoạt
- Chi phí thấp hơn cho workload ổn định, chạy 24/7
- Hỗ trợ EBS volumes, instance store
- Phải quản lý, patch, scale EC2 instances
- Cần capacity planning — dễ over/under provision
- Phải cài đặt và maintain ECS Agent
- Phức tạp hơn khi setup cluster auto scaling
- Tốn thời gian vận hành (OS updates, security patches)
- Không cần quản lý server — hoàn toàn serverless
- Tự động scale, không cần capacity planning
- Bảo mật tốt hơn — mỗi task có kernel riêng
- Trả tiền theo giây (vCPU + memory thực dùng)
- Giảm operational overhead đáng kể
- Đắt hơn EC2 cho workload chạy liên tục
- Không hỗ trợ GPU (tính đến 2024)
- Giới hạn CPU/memory (max 16 vCPU, 120 GB)
- Không dùng được Docker volumes, chỉ có EFS
- Cold start có thể mất 30-60 giây
Bảng so sánh chi tiết
| Tiêu chí | EC2 Launch Type | Fargate Launch Type |
|---|---|---|
| Quản lý server | Bạn quản lý EC2 instances | AWS quản lý hoàn toàn |
| Pricing | Trả theo EC2 instance (On-Demand/Spot/RI) | Trả theo vCPU + memory/giây |
| Max CPU/Task | Phụ thuộc instance type | 16 vCPU |
| Max Memory/Task | Phụ thuộc instance type | 120 GB |
| GPU | Có | Không |
| Spot support | Có | Có (Fargate Spot) |
| Storage | EBS, Instance Store, EFS | Ephemeral 20-200 GB, EFS |
| Network mode | awsvpc, bridge, host, none | Chỉ awsvpc |
| Startup time | Nhanh (nếu instance sẵn sàng) | 30-60 giây (cold start) |
| Placement strategies | Có | Không |
| Daemon tasks | Có | Không |
ECS Task Definition — Chi tiết
Task Definition là bản thiết kế (blueprint) mô tả cách container chạy trong ECS. Nó tương tự như docker-compose.yml nhưng dành riêng cho ECS. Mỗi Task Definition có thể chứa tối đa 10 container definitions.
Các thành phần quan trọng
| Thành phần | Mô tả | Bắt buộc |
|---|---|---|
| family | Tên nhóm cho task definition (dùng để versioning) | Có |
| containerDefinitions | Mảng các container cần chạy trong task | Có |
| cpu / memory | Tổng CPU/memory cho task (bắt buộc với Fargate) | Fargate: Có |
| networkMode | awsvpc, bridge, host, none | Không |
| taskRoleArn | IAM Role cho container gọi AWS API | Không |
| executionRoleArn | IAM Role cho ECS Agent (pull image, push logs) | Fargate: Có |
| volumes | Định nghĩa volumes (EFS, Docker, bind mount) | Không |
| requiresCompatibilities | EC2, FARGATE, hoặc EXTERNAL | Không |
| runtimePlatform | OS family (LINUX, WINDOWS) và CPU architecture (X86_64, ARM64) | Fargate: Có |
Ví dụ Task Definition hoàn chỉnh
{
"family": "my-web-app",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "512",
"memory": "1024",
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "web-app",
"image": "123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-app:latest",
"essential": true,
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp",
"appProtocol": "http"
}
],
"cpu": 256,
"memory": 512,
"memoryReservation": 256,
"environment": [
{ "name": "NODE_ENV", "value": "production" },
{ "name": "PORT", "value": "8080" }
],
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:ap-southeast-1:123456789012:secret:db-pass"
},
{
"name": "API_KEY",
"valueFrom": "arn:aws:ssm:ap-southeast-1:123456789012:parameter/api-key"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-web-app",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "web"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
},
"mountPoints": [
{
"sourceVolume": "efs-data",
"containerPath": "/app/data",
"readOnly": false
}
]
},
{
"name": "log-router",
"image": "amazon/aws-for-fluent-bit:latest",
"essential": false,
"cpu": 64,
"memory": 128,
"firelensConfiguration": {
"type": "fluentbit"
}
}
],
"volumes": [
{
"name": "efs-data",
"efsVolumeConfiguration": {
"fileSystemId": "fs-0123456789abcdef0",
"rootDirectory": "/app-data",
"transitEncryption": "ENABLED"
}
}
]
}
CPU / Memory — Các tổ hợp hợp lệ cho Fargate
| CPU (vCPU) | Memory (GB) hợp lệ |
|---|---|
| 0.25 vCPU (256) | 0.5, 1, 2 GB |
| 0.5 vCPU (512) | 1, 2, 3, 4 GB |
| 1 vCPU (1024) | 2, 3, 4, 5, 6, 7, 8 GB |
| 2 vCPU (2048) | 4 – 16 GB (tăng 1 GB) |
| 4 vCPU (4096) | 8 – 30 GB (tăng 1 GB) |
| 8 vCPU (8192) | 16 – 60 GB (tăng 4 GB) |
| 16 vCPU (16384) | 32 – 120 GB (tăng 8 GB) |
Task Role vs Execution Role
- Quyền cho ứng dụng bên trong container
- Ví dụ: đọc S3, ghi DynamoDB, gửi SQS
- Tương tự EC2 Instance Profile
- Mỗi task definition có thể có role riêng
- Quyền cho ECS Agent thực hiện tác vụ hệ thống
- Pull image từ ECR
- Push logs lên CloudWatch
- Lấy secrets từ Secrets Manager / SSM
- environment: Dùng cho giá trị không nhạy cảm (NODE_ENV, PORT, LOG_LEVEL)
- secrets: Dùng cho giá trị nhạy cảm — lấy từ Secrets Manager hoặc SSM Parameter Store
- Secrets được inject vào container lúc runtime, không lưu trong task definition
- Execution Role cần quyền
secretsmanager:GetSecretValuehoặcssm:GetParameters
ECS Service — Quản lý & Triển khai
ECS Service đảm bảo số lượng task mong muốn (desired count) luôn chạy và healthy. Nếu một task fail, service tự động khởi động task mới thay thế. Service cũng tích hợp với load balancer và hỗ trợ nhiều deployment strategies.
Deployment Strategies
Rolling Update — Cấu hình
| Tham số | Mô tả | Ví dụ (desired = 4) |
|---|---|---|
| minimumHealthyPercent | % task tối thiểu phải healthy trong quá trình deploy | 50% → ít nhất 2 task chạy |
| maximumPercent | % task tối đa có thể chạy (bao gồm cả cũ + mới) | 200% → tối đa 8 task cùng lúc |
{
"serviceName": "my-web-service",
"cluster": "production",
"taskDefinition": "my-web-app:5",
"desiredCount": 4,
"launchType": "FARGATE",
"deploymentConfiguration": {
"minimumHealthyPercent": 50,
"maximumPercent": 200,
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true
}
},
"networkConfiguration": {
"awsvpcConfiguration": {
"subnets": ["subnet-abc123", "subnet-def456"],
"securityGroups": ["sg-web-app"],
"assignPublicIp": "DISABLED"
}
},
"loadBalancers": [
{
"targetGroupArn": "arn:aws:elasticloadbalancing:...:targetgroup/my-tg/abc123",
"containerName": "web-app",
"containerPort": 8080
}
],
"healthCheckGracePeriodSeconds": 120,
"serviceConnectConfiguration": {
"enabled": true,
"namespace": "production",
"services": [
{
"portName": "http",
"clientAliases": [{ "port": 8080, "dnsName": "web-app" }]
}
]
}
}
Blue/Green Deployment với CodeDeploy
- Yêu cầu Application Load Balancer với 2 target groups (blue + green)
- CodeDeploy tạo task set mới → chạy health check → chuyển traffic
- Canary: Chuyển 10% traffic trước, đợi X phút, rồi chuyển 90% còn lại
- Linear: Chuyển traffic dần dần (ví dụ: 10% mỗi 5 phút)
- All-at-once: Chuyển 100% traffic ngay lập tức
- Rollback tự động nếu health check fail hoặc CloudWatch alarm trigger
Load Balancer Integration
| Load Balancer | Phù hợp khi | Tính năng nổi bật |
|---|---|---|
| ALB | HTTP/HTTPS traffic, microservices | Path-based routing, host-based routing, gRPC, WebSocket |
| NLB | TCP/UDP traffic, cần ultra-low latency | Static IP, preserve source IP, millions RPS |
deploymentCircuitBreaker với rollback: true, ECS sẽ tự động rollback về task definition trước đó nếu deployment thất bại liên tục. Đây là tính năng quan trọng cho production — luôn bật để tránh downtime kéo dài.
Amazon EKS — Kiến trúc
Amazon Elastic Kubernetes Service (EKS) là dịch vụ Kubernetes được quản lý, giúp bạn chạy Kubernetes trên AWS mà không cần cài đặt và vận hành control plane. EKS tương thích 100% với Kubernetes upstream, nghĩa là mọi plugin, tool và workload K8s đều hoạt động.
Các thành phần chính
Sơ đồ kiến trúc EKS
Managed Node Groups vs Self-Managed Nodes
| Tiêu chí | Managed Node Groups | Self-Managed Nodes |
|---|---|---|
| Provisioning | AWS tự động tạo ASG, Launch Template | Bạn tự tạo và cấu hình |
| OS Updates | Managed update — rolling, tự drain nodes | Bạn tự update AMI, drain nodes |
| Custom AMI | Có (từ 2021) | Có |
| Spot Instances | Có | Có |
| GPU | Có | Có |
| Taints/Labels | Cấu hình qua API/Console | Cấu hình qua bootstrap script |
| Độ phức tạp | Thấp | Cao |
EKS với Fargate
EKS hỗ trợ chạy pods trên AWS Fargate — mỗi pod chạy trong một microVM riêng biệt, hoàn toàn serverless. Bạn định nghĩa Fargate Profile để chỉ định pods nào chạy trên Fargate dựa trên namespace và labels.
Fargate Profile
# Tạo Fargate Profile qua eksctl
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: ap-southeast-1
fargateProfiles:
- name: fp-default
selectors:
- namespace: default
labels:
compute: fargate
- namespace: staging
# Pods trong namespace "default" có label compute=fargate
# HOẶC tất cả pods trong namespace "staging"
# → sẽ chạy trên Fargate
- name: fp-coredns
selectors:
- namespace: kube-system
labels:
k8s-app: kube-dns
# CoreDNS cũng có thể chạy trên Fargate
aws eks create-fargate-profile \
--cluster-name my-cluster \
--fargate-profile-name fp-default \
--pod-execution-role-arn arn:aws:iam::123456789012:role/eksFargatePodRole \
--subnets subnet-abc123 subnet-def456 \
--selectors namespace=default,labels={compute=fargate}
Giới hạn của EKS Fargate
- Không hỗ trợ DaemonSets — không thể chạy agent trên mỗi node
- Không hỗ trợ Privileged containers
- Không hỗ trợ GPU
- Không hỗ trợ HostNetwork, HostPort
- Chỉ hỗ trợ ALB (qua AWS Load Balancer Controller), không hỗ trợ NLB trực tiếp
- Storage chỉ hỗ trợ EFS, không hỗ trợ EBS
- Max 4 vCPU, 30 GB memory per pod
- Mỗi pod có 20 GB ephemeral storage mặc định
Khi nào dùng EKS Fargate?
- Microservices stateless, không cần GPU
- Batch jobs, cron jobs chạy định kỳ
- Workload cần isolation cao (multi-tenant)
- Team nhỏ, không muốn quản lý nodes
- Dev/staging environments
- Cần DaemonSets (monitoring agents, log collectors)
- Workload cần GPU (ML/AI training)
- Cần EBS persistent volumes
- Ứng dụng cần privileged mode
- Workload cần hơn 4 vCPU hoặc 30 GB RAM
Networking — Container Networking trên AWS
Networking là phần phức tạp nhất khi chạy container. AWS cung cấp nhiều network mode và dịch vụ hỗ trợ service discovery, service mesh để kết nối các container với nhau.
ECS Network Modes
| Network Mode | Mô tả | Fargate | Use Case |
|---|---|---|---|
| awsvpc | Mỗi task có ENI riêng với IP trong VPC subnet. Bắt buộc cho Fargate. | Bắt buộc | Production, cần security group per task |
| bridge | Dùng Docker bridge network. Nhiều container share host IP, dùng dynamic port mapping. | Không | Legacy, nhiều task trên 1 instance |
| host | Container dùng trực tiếp network namespace của host. Hiệu năng cao nhất. | Không | Cần hiệu năng network tối đa |
| none | Container không có external network connectivity. | Không | Batch processing offline |
- Mỗi task nhận một Elastic Network Interface (ENI) riêng
- Task có private IP trong VPC subnet → áp dụng Security Group trực tiếp
- Giới hạn: số ENI phụ thuộc instance type (ví dụ: t3.medium = 3 ENI = 3 tasks)
- Giải pháp: bật ENI Trunking để tăng số task per instance lên đáng kể
- Fargate: mỗi task tự động có ENI, không giới hạn bởi instance type
EKS Networking — VPC CNI Plugin
EKS sử dụng Amazon VPC CNI Plugin để gán IP address từ VPC subnet cho mỗi pod. Mỗi pod nhận một secondary IP từ ENI của node.
# Kiểm tra VPC CNI version kubectl describe daemonset aws-node -n kube-system | grep Image # Xem IP allocation trên node kubectl get nodes -o wide # Bật prefix delegation để tăng pod density kubectl set env daemonset aws-node -n kube-system \ ENABLE_PREFIX_DELEGATION=true \ WARM_PREFIX_TARGET=1
Service Discovery
ECS Service Connect — Ví dụ
{
"serviceConnectConfiguration": {
"enabled": true,
"namespace": "production",
"services": [
{
"portName": "http",
"discoveryName": "api-service",
"clientAliases": [
{ "port": 8080, "dnsName": "api-service" }
]
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/service-connect-proxy",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "proxy"
}
}
}
}
// Các service khác gọi: http://api-service:8080
Sơ đồ Networking — awsvpc mode
Storage cho Container
Container mặc định là ephemeral — dữ liệu mất khi container dừng. Để persistent storage, AWS cung cấp nhiều giải pháp tích hợp với ECS và EKS thông qua CSI drivers.
Các loại Storage
| Storage | Loại | ECS | EKS | Fargate | Use Case |
|---|---|---|---|---|---|
| Amazon EFS | File (NFS) | Có | Có | Có | Shared storage giữa nhiều tasks/pods, CMS, ML data |
| Amazon EBS | Block | EC2 only | Có (CSI) | Không | Database, high IOPS workloads |
| Amazon FSx | File (Lustre/NetApp) | Hạn chế | Có (CSI) | Không | HPC, ML training, Windows workloads |
| Ephemeral | Local | Có | Có | 20-200 GB | Temp files, cache, scratch space |
| Docker Volumes | Plugin-based | EC2 only | N/A | Không | Third-party storage plugins |
EFS với ECS — Cấu hình trong Task Definition
{
"volumes": [
{
"name": "shared-data",
"efsVolumeConfiguration": {
"fileSystemId": "fs-0123456789abcdef0",
"rootDirectory": "/",
"transitEncryption": "ENABLED",
"transitEncryptionPort": 2049,
"authorizationConfig": {
"accessPointId": "fsap-0123456789abcdef0",
"iam": "ENABLED"
}
}
}
],
"containerDefinitions": [
{
"name": "app",
"mountPoints": [
{
"sourceVolume": "shared-data",
"containerPath": "/mnt/efs",
"readOnly": false
}
]
}
]
}
EBS CSI Driver cho EKS
# Cài đặt EBS CSI Driver (EKS Add-on)
aws eks create-addon \
--cluster-name my-cluster \
--addon-name aws-ebs-csi-driver \
--service-account-role-arn arn:aws:iam::123456789012:role/EBS_CSI_DriverRole
---
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes: [ReadWriteOnce]
storageClassName: ebs-gp3
resources:
requests:
storage: 50Gi
- EFS: Dùng khi cần shared storage giữa nhiều tasks/pods hoặc khi dùng Fargate
- EBS: Dùng cho database, cần high IOPS. Chỉ attach vào 1 pod (ReadWriteOnce)
- Luôn bật transit encryption cho EFS
- Dùng EFS Access Points để phân quyền thư mục cho từng service
- Với EKS, cài EBS CSI Driver và EFS CSI Driver qua EKS Add-ons
Auto Scaling cho Container
Auto Scaling cho container có hai tầng: Application-level (scale số task/pod) và Infrastructure-level (scale số node/instance). Cả hai cần phối hợp để đảm bảo ứng dụng luôn có đủ tài nguyên.
ECS Service Auto Scaling
Sử dụng Application Auto Scaling để tự động điều chỉnh desired count của ECS Service.
| Scaling Policy | Mô tả | Phù hợp khi |
|---|---|---|
| Target Tracking | Giữ metric ở mức target (ví dụ: CPU = 70%) | Workload có pattern rõ ràng, muốn đơn giản |
| Step Scaling | Scale theo bậc dựa trên CloudWatch Alarm | Cần kiểm soát chính xác số task thêm/bớt |
| Scheduled Scaling | Scale theo lịch (cron expression) | Traffic có pattern theo giờ/ngày (ví dụ: giờ cao điểm) |
# Đăng ký scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/production/my-web-service \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 20
# Target Tracking — CPU 70%
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/production/my-web-service \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-target-tracking \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
ECS Cluster Auto Scaling (EC2 Launch Type)
Khi dùng EC2 launch type, cần scale cả EC2 instances trong cluster. ECS sử dụng Capacity Provider kết hợp với ASG để tự động thêm/bớt instances.
# Tạo Capacity Provider
aws ecs create-capacity-provider \
--name my-cp \
--auto-scaling-group-provider '{
"autoScalingGroupArn": "arn:aws:autoscaling:...:autoScalingGroup:...",
"managedScaling": {
"status": "ENABLED",
"targetCapacity": 80,
"minimumScalingStepSize": 1,
"maximumScalingStepSize": 10
},
"managedTerminationProtection": "ENABLED"
}'
# Gán Capacity Provider vào Cluster
aws ecs put-cluster-capacity-providers \
--cluster production \
--capacity-providers my-cp FARGATE FARGATE_SPOT \
--default-capacity-provider-strategy '[
{"capacityProvider": "my-cp", "weight": 1, "base": 2},
{"capacityProvider": "FARGATE_SPOT", "weight": 1}
]'
Karpenter cho EKS
Karpenter là node autoscaler thế hệ mới cho Kubernetes, thay thế Cluster Autoscaler. Karpenter trực tiếp provision EC2 instances phù hợp nhất cho pending pods, không cần cấu hình ASG hay Node Groups.
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]
nodeClassRef:
name: default
limits:
cpu: "100"
memory: 400Gi
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h # 30 ngày
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: my-cluster
- Karpenter: Nhanh hơn (provision trong giây), tự chọn instance type tối ưu, consolidation tự động
- Cluster Autoscaler: Phụ thuộc ASG, chậm hơn (phút), cần cấu hình node groups trước
- Khuyến nghị: Dùng Karpenter cho EKS clusters mới
Security — Bảo mật Container
Bảo mật container bao gồm nhiều tầng: từ image security, runtime security, network security đến secrets management. AWS cung cấp nhiều công cụ tích hợp sẵn.
IAM Roles cho Container
| Role | Dùng cho | ECS | EKS |
|---|---|---|---|
| Task Role | Ứng dụng trong container gọi AWS API | taskRoleArn | IRSA / Pod Identity |
| Execution Role | ECS Agent pull image, push logs, get secrets | executionRoleArn | Node IAM Role |
| Instance Role | EC2 instance đăng ký vào cluster | EC2 Instance Profile | Node IAM Role |
EKS — IAM Roles for Service Accounts (IRSA)
# 1. Tạo OIDC Provider cho cluster eksctl utils associate-iam-oidc-provider \ --cluster my-cluster --approve # 2. Tạo IAM Role + Service Account eksctl create iamserviceaccount \ --cluster my-cluster \ --namespace default \ --name my-app-sa \ --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \ --approve # 3. Sử dụng trong Pod spec # serviceAccountName: my-app-sa
EKS Pod Identity (Mới — Đơn giản hơn IRSA)
# Cài EKS Pod Identity Agent add-on aws eks create-addon \ --cluster-name my-cluster \ --addon-name eks-pod-identity-agent # Tạo Pod Identity Association aws eks create-pod-identity-association \ --cluster-name my-cluster \ --namespace default \ --service-account my-app-sa \ --role-arn arn:aws:iam::123456789012:role/my-app-role
Amazon ECR — Container Registry
# Login vào ECR aws ecr get-login-password --region ap-southeast-1 | \ docker login --username AWS --password-stdin \ 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com # Build và push docker build -t my-app:v1.0 . docker tag my-app:v1.0 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-app:v1.0 docker push 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-app:v1.0 # Bật image scanning aws ecr put-image-scanning-configuration \ --repository-name my-app \ --image-scanning-configuration scanOnPush=true
Secrets Management
- Lưu trữ database credentials, API keys, certificates
- Tự động rotate secrets
- Phí: $0.40/secret/tháng + $0.05/10,000 API calls
- Tích hợp trực tiếp với ECS task definition (
secrets)
- Lưu trữ configuration values, feature flags
- Standard tier: miễn phí (10,000 parameters)
- Advanced tier: $0.05/parameter/tháng
- Tích hợp với ECS qua
secrets(valueFrom = SSM ARN)
- KHÔNG hardcode secrets trong Dockerfile hoặc environment variables của task definition
- KHÔNG dùng
rootuser trong container — tạo non-root user - KHÔNG dùng
latesttag — luôn pin version cụ thể - KHÔNG bỏ qua image scanning — bật scanOnPush cho mọi repository
- KHÔNG dùng public ECR cho production images
Monitoring — Giám sát Container
Giám sát container cần theo dõi nhiều tầng: infrastructure metrics, application metrics, logs và traces. AWS cung cấp CloudWatch Container Insights như giải pháp tích hợp sẵn.
CloudWatch Container Insights
# Bật Container Insights khi tạo cluster
aws ecs create-cluster \
--cluster-name production \
--settings name=containerInsights,value=enabled
# Hoặc update cluster hiện có
aws ecs update-cluster-settings \
--cluster production \
--settings name=containerInsights,value=enabled
# Log configuration trong task definition
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-app",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "app",
"awslogs-create-group": "true"
}
}
Prometheus + Grafana cho EKS
# Cài đặt qua Helm helm repo add prometheus-community \ https://prometheus-community.github.io/helm-charts helm repo update # Cài kube-prometheus-stack (Prometheus + Grafana + AlertManager) helm install monitoring prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --create-namespace \ --set grafana.adminPassword=your-password \ --set prometheus.prometheusSpec.retention=30d \ --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi # Hoặc dùng Amazon Managed Prometheus (AMP) aws amp create-workspace --alias my-prometheus # Và Amazon Managed Grafana (AMG) # → Cấu hình qua AWS Console
FireLens — Log Routing nâng cao
// Trong task definition — thêm FireLens container
{
"name": "log-router",
"image": "amazon/aws-for-fluent-bit:stable",
"essential": true,
"firelensConfiguration": {
"type": "fluentbit",
"options": {
"config-file-type": "file",
"config-file-value": "/fluent-bit/configs/custom.conf"
}
}
}
// App container — gửi logs qua FireLens
{
"name": "app",
"logConfiguration": {
"logDriver": "awsfirelens",
"options": {
"Name": "cloudwatch_logs",
"region": "ap-southeast-1",
"log_group_name": "/ecs/my-app",
"log_stream_prefix": "app-",
"auto_create_group": "true"
}
}
}
- Luôn bật Container Insights cho mọi ECS cluster
- Dùng FireLens thay vì awslogs driver khi cần gửi logs đến nhiều đích (S3, Elasticsearch, Datadog)
- Tạo CloudWatch Dashboard cho mỗi service với CPU, Memory, Request Count, Error Rate
- Đặt alarm cho: CPU > 80%, Memory > 85%, Task count < desired, 5xx error rate > 1%
- Với EKS, cân nhắc Amazon Managed Prometheus + Grafana để giảm operational overhead
Các lỗi thường gặp & Best Practices
Lỗi thường gặp — ECS
| Lỗi | Nguyên nhân | Giải pháp |
|---|---|---|
| Task stopped: CannotPullContainerError | Không pull được image từ ECR/DockerHub | Kiểm tra Execution Role có quyền ecr:GetDownloadUrlForLayer. Nếu Fargate private subnet → cần NAT Gateway hoặc VPC Endpoint cho ECR. |
| Task stopped: ResourceNotFoundException | Task definition hoặc cluster không tồn tại | Kiểm tra tên cluster, task definition ARN, region. |
| Service stuck: tasks keep stopping | Container crash loop, health check fail | Kiểm tra container logs trong CloudWatch. Tăng healthCheckGracePeriodSeconds. Kiểm tra health check endpoint. |
| RESOURCE:MEMORY — không đủ memory | Cluster không đủ memory cho task | Thêm EC2 instances hoặc dùng Fargate. Kiểm tra memory reservation vs hard limit. |
| RESOURCE:ENI — hết ENI | awsvpc mode: mỗi task cần 1 ENI, instance hết slot | Bật ENI Trunking hoặc dùng instance type lớn hơn. Hoặc chuyển sang Fargate. |
| Secrets: AccessDeniedException | Execution Role thiếu quyền đọc secrets | Thêm secretsmanager:GetSecretValue hoặc ssm:GetParameters vào Execution Role. |
Lỗi thường gặp — EKS
| Lỗi | Nguyên nhân | Giải pháp |
|---|---|---|
| Pods stuck in Pending | Không đủ node resources (CPU/memory) | Kiểm tra kubectl describe pod. Scale node group hoặc cài Karpenter. |
| ImagePullBackOff | Không pull được image | Kiểm tra ECR permissions, image tag tồn tại, network connectivity. |
| CrashLoopBackOff | Container crash liên tục | kubectl logs pod-name --previous để xem logs lần chạy trước. |
| Node NotReady | kubelet không communicate được với API server | Kiểm tra Security Group, VPC CNI, disk space, kubelet logs. |
| Service không có external IP | Thiếu AWS Load Balancer Controller | Cài AWS Load Balancer Controller. Kiểm tra subnet tags cho auto-discovery. |
| Pod cannot reach other pods | VPC CNI issue, Security Group chặn | Kiểm tra aws-node DaemonSet, Security Group rules, Network Policy. |
Best Practices
🏗 Kiến trúc
- Mỗi container chỉ chạy một process — tách web server, worker, cron thành các task/pod riêng
- Dùng multi-stage Docker builds để giảm image size
- Đặt container trong private subnets, expose qua ALB/NLB
- Dùng Service Connect (ECS) hoặc Service Mesh (EKS) cho service-to-service communication
- Thiết kế ứng dụng stateless — lưu state vào external store (RDS, ElastiCache, S3)
💰 Chi phí
- Dùng Fargate Spot cho non-critical workloads (tiết kiệm 70%)
- Dùng EC2 Spot Instances cho ECS/EKS worker nodes (tiết kiệm 90%)
- Dùng Graviton (ARM64) instances — hiệu năng/giá tốt hơn 20-40%
- Right-size CPU/memory — dùng Container Insights để phân tích actual usage
- Dùng Savings Plans (Compute) cho workload ổn định
- Bật ECR Lifecycle Policies để xóa images cũ, tiết kiệm storage
🔐 Bảo mật
- Luôn dùng non-root user trong Dockerfile
- Pin image version cụ thể — không dùng
:latest - Bật image scanning (ECR Enhanced Scanning với Inspector)
- Dùng IAM Roles for Tasks/Pods — không dùng access keys
- Lưu secrets trong Secrets Manager, không hardcode
- Bật encryption in transit (TLS) cho mọi communication
- Dùng read-only root filesystem khi có thể
- Giới hạn Security Group chỉ cho phép traffic cần thiết
🚀 Deployment
- Luôn bật Deployment Circuit Breaker với auto rollback
- Dùng Blue/Green deployment cho production critical services
- Cấu hình health check đúng — startPeriod đủ lớn cho container khởi động
- Implement graceful shutdown — handle SIGTERM signal
- Dùng CI/CD pipeline (CodePipeline, GitHub Actions) cho automated deployments
- Tag images với git commit SHA để traceability
AWS CLI & kubectl Cheat Sheet
ECS — AWS CLI
# ═══ CLUSTER ═══ # Tạo cluster aws ecs create-cluster --cluster-name production \ --settings name=containerInsights,value=enabled # Liệt kê clusters aws ecs list-clusters # Xem chi tiết cluster aws ecs describe-clusters --clusters production \ --include STATISTICS ATTACHMENTS # Xóa cluster aws ecs delete-cluster --cluster production
# ═══ TASK DEFINITION ═══
# Đăng ký task definition
aws ecs register-task-definition --cli-input-json file://task-def.json
# Liệt kê task definitions
aws ecs list-task-definitions --family-prefix my-web-app
# Xem chi tiết
aws ecs describe-task-definition --task-definition my-web-app:5
# Deregister (không xóa, chỉ đánh dấu INACTIVE)
aws ecs deregister-task-definition --task-definition my-web-app:3
# ═══ RUN TASK (standalone) ═══
aws ecs run-task \
--cluster production \
--task-definition my-batch-job:1 \
--launch-type FARGATE \
--network-configuration '{
"awsvpcConfiguration": {
"subnets": ["subnet-abc123"],
"securityGroups": ["sg-batch"],
"assignPublicIp": "DISABLED"
}
}'
# Dừng task
aws ecs stop-task --cluster production --task arn:aws:ecs:...:task/abc123
# Liệt kê tasks đang chạy
aws ecs list-tasks --cluster production --service-name my-web-service
# ═══ SERVICE ═══ # Tạo service aws ecs create-service --cli-input-json file://service.json # Update service (deploy new task definition) aws ecs update-service \ --cluster production \ --service my-web-service \ --task-definition my-web-app:6 \ --force-new-deployment # Scale service aws ecs update-service \ --cluster production \ --service my-web-service \ --desired-count 8 # Xem events (troubleshooting) aws ecs describe-services \ --cluster production \ --services my-web-service \ --query 'services[0].events[:10]' # Xóa service (phải set desired-count = 0 trước) aws ecs update-service --cluster production --service my-web-service --desired-count 0 aws ecs delete-service --cluster production --service my-web-service
# Bật ECS Exec cho service aws ecs update-service \ --cluster production \ --service my-web-service \ --enable-execute-command # SSH vào container đang chạy aws ecs execute-command \ --cluster production \ --task arn:aws:ecs:...:task/abc123 \ --container web-app \ --interactive \ --command "/bin/sh"
ECR — Container Registry
# Login
aws ecr get-login-password --region ap-southeast-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-southeast-1.amazonaws.com
# Tạo repository
aws ecr create-repository --repository-name my-app \
--image-scanning-configuration scanOnPush=true \
--encryption-configuration encryptionType=AES256
# Liệt kê images
aws ecr list-images --repository-name my-app
# Xem scan results
aws ecr describe-image-scan-findings \
--repository-name my-app \
--image-id imageTag=v1.0
# Lifecycle policy — giữ 10 images mới nhất
aws ecr put-lifecycle-policy --repository-name my-app \
--lifecycle-policy-text '{
"rules": [{
"rulePriority": 1,
"description": "Keep last 10 images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
}]
}'
EKS — eksctl & kubectl
# ═══ CLUSTER ═══ # Tạo cluster với eksctl eksctl create cluster \ --name my-cluster \ --region ap-southeast-1 \ --version 1.29 \ --nodegroup-name workers \ --node-type t3.medium \ --nodes 3 \ --nodes-min 2 \ --nodes-max 10 \ --managed # Cấu hình kubectl aws eks update-kubeconfig --name my-cluster --region ap-southeast-1 # Kiểm tra kết nối kubectl cluster-info kubectl get nodes # Xem EKS add-ons aws eks list-addons --cluster-name my-cluster
# ═══ DEPLOYMENTS ═══ # Tạo deployment kubectl create deployment nginx --image=nginx:1.25 --replicas=3 # Apply từ file YAML kubectl apply -f deployment.yaml # Scale kubectl scale deployment nginx --replicas=5 # Rolling update kubectl set image deployment/nginx nginx=nginx:1.26 # Xem rollout status kubectl rollout status deployment/nginx # Rollback kubectl rollout undo deployment/nginx kubectl rollout undo deployment/nginx --to-revision=2 # Xem history kubectl rollout history deployment/nginx # ═══ PODS ═══ # Liệt kê pods kubectl get pods -o wide kubectl get pods --all-namespaces # Xem chi tiết pod kubectl describe pod pod-name # Xem logs kubectl logs pod-name kubectl logs pod-name -c container-name # multi-container kubectl logs pod-name --previous # previous crash kubectl logs -f pod-name # follow/stream # Exec vào pod kubectl exec -it pod-name -- /bin/sh # Port forward kubectl port-forward pod-name 8080:80 kubectl port-forward svc/my-service 8080:80 # ═══ SERVICES ═══ # Expose deployment kubectl expose deployment nginx --port=80 --type=LoadBalancer # Liệt kê services kubectl get svc # ═══ DEBUG ═══ # Xem events kubectl get events --sort-by='.lastTimestamp' # Top (resource usage) kubectl top nodes kubectl top pods # Xem resource quotas kubectl describe resourcequota -n my-namespace
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: my-app-sa
containers:
- name: app
image: 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-app:v1.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: my-app
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: production
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- ECS Developer Guide: docs.aws.amazon.com/AmazonECS/latest/developerguide/
- EKS User Guide: docs.aws.amazon.com/eks/latest/userguide/
- ECR User Guide: docs.aws.amazon.com/AmazonECR/latest/userguide/
- Karpenter Docs: karpenter.sh/docs/
- ECS Workshop: ecsworkshop.com
- EKS Workshop: eksworkshop.com