ComputeCompute
Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.
Tổng quan
Compute là nơi code của bạn thực sự chạy, và AWS cung cấp một phổ các lựa chọn đánh đổi giữa mức độ kiểm soát và sự tiện lợi. Ở một đầu là EC2 — các máy ảo thô nơi bạn sở hữu OS, runtime và việc scaling. Ở đầu kia là Lambda — các function thuần túy nơi bạn không sở hữu gì ngoài code còn AWS lo mọi server. Ở giữa là containers (ECS, EKS, App Runner) và các nền tảng ứng dụng được quản lý (Elastic Beanstalk). Nghệ thuật của compute trên AWS không nằm ở việc biết mọi service — mà nằm ở việc khớp hình dạng của workload (chạy dài hạn vs bùng nổ ngắn hạn, có trạng thái vs không trạng thái, ổn định vs biến động mạnh) với mô hình tốn ít công vận hành nhất cho mức độ tin cậy mà bạn cần.
Trang này đi dọc theo phổ đó, từ VM lên tới function. Nó bao gồm EC2 (họ instance, AMI, các phương án mua, user data), Auto Scaling (Launch Template và Auto Scaling Group biến một instance thành một fleet co giãn), ngăn xếp container (ECS với EC2 vs Fargate, EKS cho Kubernetes, ECR cho image, App Runner cho trường hợp đơn giản), Lambda (event source, concurrency, layer, cold start), và Batch cho các job batch quy mô lớn. Nó kết thúc bằng hướng dẫn ra quyết định — khi nào tôi nên chọn một VM, một container, hay một function? — bởi vì lựa chọn đầu tiên đó định hình mọi thứ phía sau.
Một cách nhìn hữu ích: mọi compute service đều trả lời cùng ba câu hỏi theo cách khác nhau — ai vá OS, ai quyết định chạy bao nhiêu bản sao, và ai trả tiền cho thời gian nhàn rỗi? Trên EC2 câu trả lời cho cả ba là “bạn”. Trên Fargate bạn ngừng vá host. Trên Lambda bạn ngừng trả tiền cho thời gian nhàn rỗi hoàn toàn. Chỉ leo lên nấc thang đúng bằng mức mà workload cho phép, không hơn.
Tại sao lựa chọn compute lại quan trọng
Quyết định về compute là quyết định bạn xem lại ít nhất mà trả giá nhiều nhất. Một workload được xây như một monolith trên EC2 tự quản lý sẽ tích lũy công vá lỗi, scaling và trực on-call mỗi ngày; cũng workload đó dưới dạng một service Fargate hoặc một Lambda sẽ trút bỏ phần lớn gánh nặng ấy. Nhưng leo nấc thang không miễn phí — Lambda áp trần 15 phút và độ trễ cold-start, container áp một đường cong học tập về orchestration, và serverless có thể tốn nhiều hơn một VM reserved ở mức tải cao ổn định. Chọn đúng nghĩa là thành thật về hình dạng thực của workload thay vì theo phản xạ chọn mô hình mới nhất.
Kiến thức nền tảng
EC2 — Elastic Compute Cloud
EC2 cung cấp các máy ảo có thể thay đổi kích thước (“instances”) được khởi chạy từ một image (AMI) lên một loại instance đã chọn, bên trong một VPC subnet, kèm storage gắn vào và một security group. Đây là compute service lâu đời và linh hoạt nhất của AWS và là nền tảng bên dưới nhiều service khác (EKS node, ECS on EC2, EMR, và nhiều hơn nữa đều chạy trên nó).
Họ instance nhóm phần cứng theo hồ sơ workload. Tên mã hóa họ, thế hệ và kích thước — ví dụ m7g.xlarge là họ m, thế hệ 7, biến thể g (Graviton/ARM), ở kích thước xlarge.
| Họ | Tối ưu cho | Ví dụ | Trường hợp dùng điển hình |
|---|---|---|---|
| T (burstable) | CPU nền + tín dụng burst | t3, t4g | Máy dev, web ít lưu lượng, microservice có thời gian nhàn rỗi |
| M (general) | Cân bằng CPU:bộ nhớ (≈1:4) | m6i, m7g | Web/app server, database nhỏ, hầu hết workload |
| C (compute) | CPU cao so với bộ nhớ | c6i, c7g | Batch, encoding, HPC, game server, API thông lượng cao |
| R (memory) | Bộ nhớ cao (≈1:8) | r6i, r7g | Cache in-memory, database lớn, analytics |
| X / u (bộ nhớ lớn) | Bộ nhớ cực lớn (hàng TB) | x2idn, u-6tb1 | SAP HANA, DB in-memory khổng lồ |
| I / D (storage) | Thông lượng NVMe/HDD cục bộ | i4i, d3 | NoSQL, data warehouse, hệ thống file phân tán |
| P / G / Inf / Trn (tăng tốc) | GPU / bộ tăng tốc ML | p5, g5, inf2, trn1 | Training, inference, đồ họa, ML |
Graviton (ARM): các instance có hậu tố g (m7g, c7g, t4g) chạy chip ARM của chính AWS và thường mang lại hiệu năng/giá tốt hơn ~20–40% so với các bản x86 tương đương. Nếu ngăn xếp của bạn build sạch cho ARM (hầu hết các ngôn ngữ thông dịch/JIT và các ngôn ngữ biên dịch hiện đại đều được), Graviton thường là lợi ích dễ dàng.
AMI (Amazon Machine Images) là template mà instance boot từ đó — một snapshot của root volume cộng với metadata (kiến trúc, loại ảo hóa, block-device mapping). Chúng đến dưới dạng do AWS cung cấp (Amazon Linux 2023, Ubuntu, Windows), Marketplace, hoặc golden image của riêng bạn được “nướng” sẵn bằng các công cụ như Packer. Nướng các phụ thuộc vào một AMI (“hạ tầng bất biến”) giúp việc khởi chạy nhanh và tất định; giải pháp thay thế là provisioning lúc boot (xem user data).
User data là một script (shell hoặc cloud-init) được truyền vào lúc khởi chạy và chạy một lần khi boot lần đầu — hook bootstrapping để cài package, kéo config, hoặc đăng ký với một cluster. Giữ nó nhỏ và idempotent; script user-data nặng làm chậm việc khởi chạy và là nguồn phổ biến của các lỗi kiểu “chạy được khi relaunch, hỏng khi scale-out”. Thay vào đó hãy nướng phần cài đặt nặng vào AMI.
Instance metadata service (IMDS): mọi instance có thể truy vấn http://169.254.169.254/ để lấy metadata của chính nó (instance ID, region, credential của IAM role). Luôn yêu cầu IMDSv2 (dựa trên token) — IMDSv1 là vector trong nhiều vụ vi phạm SSRF-đến-đánh-cắp-credential nổi tiếng.
Các phương án mua (cũng được đề cập ở trang Tổng quan):
| Phương án | Chiết khấu | Cam kết | Dùng cho |
|---|---|---|---|
| On-Demand | 0% (mốc cơ sở) | Không | Biến động, ngắn hạn, khó dự đoán |
| Savings Plans | tới ~72% | 1/3 năm $/giờ | Compute nền ổn định |
| Reserved Instances | tới ~72% | 1/3 năm, loại cụ thể | Sử dụng ổn định, dễ dự đoán |
| Spot | tới ~90% | Không (thông báo thu hồi 2 phút) | Chịu lỗi, có thể gián đoạn |
| Dedicated Hosts | phụ phí | Tùy chọn | Cấp phép BYOL, cách ly vật lý |
Auto Scaling Groups và Launch Templates
Một instance đơn lẻ là một thú cưng với một điểm lỗi duy nhất. Một Auto Scaling Group (ASG) biến nó thành đàn gia súc: một fleet được quản lý duy trì số lượng mục tiêu, thay thế các instance không khỏe, và phình ra hay co lại theo nhu cầu trên nhiều AZ.
- Launch Template — công thức cho một instance: AMI, (các) loại instance, key pair, security group, IAM instance profile, user data, block device. Template có phiên bản (Launch Configuration, dạng cũ hơn, thì không — luôn dùng template).
- Desired / min / max capacity — ASG giữ
desiredinstance chạy, không bao giờ ít hơnminhoặc nhiều hơnmax. - Health check — EC2 status check và/hoặc ELB health check; một instance lỗi bị chấm dứt và thay thế tự động.
- Scaling policy — target tracking (giữ CPU trung bình ở 50%), step scaling (thêm N khi một CloudWatch alarm kích hoạt), scheduled (scale lên trước giờ làm việc), hoặc predictive (dự báo nhu cầu bằng ML).
- Multi-AZ — cung cấp subnet ở ≥2 AZ và ASG cân bằng instance giữa chúng, để một AZ hỏng chỉ mất một phần dung lượng.
ASG kết hợp với một Application Load Balancer (ALB) hoặc Network Load Balancer (NLB): ASG đăng ký instance mới với một target group, LB ngừng định tuyến tới các instance đang draining, và việc thay thế cuốn chiếu diễn ra không downtime. Đây là mẫu web-tier chịu lỗi kinh điển.
Elastic Beanstalk
Elastic Beanstalk là một lớp PaaS trên EC2, ASG, ELB và CloudWatch: bạn đưa cho nó code (một JAR, một container, một zip) cộng với một nền tảng (Java, Node, Python, .NET, Docker) và nó provisioning cùng quản lý ngăn xếp bên dưới cho bạn, bao gồm rolling deploy và dashboard sức khỏe. Đây là đường vào nhanh cho các đội muốn “chỉ cần deploy app của tôi” mà không phải tự nối dây các primitive — nhưng bạn vẫn giữ quyền truy cập vào các tài nguyên mà nó tạo ra. Trong thực hành hiện đại nó phần lớn đã bị thay thế bởi container (ECS/App Runner) và IaC, nhưng nó vẫn là lựa chọn hợp lý cho các web app đơn giản và cho việc đưa một app legacy lên AWS với tối thiểu công sửa lại.
Khái niệm chính
Containers trên AWS
Container đóng gói một app cùng các phụ thuộc của nó vào một image di động. AWS cung cấp một ngăn xếp đầy đủ quanh chúng:
ECR — Elastic Container Registry là registry image riêng tư được quản lý. Push image bằng docker push, quét chúng tìm CVE khi push, áp lifecycle policy để hết hạn các tag cũ, và pull chúng vào ECS/EKS/Lambda. Đây là nơi mặc định cho image của bạn.
ECS — Elastic Container Service là orchestrator container của chính AWS — đơn giản hơn Kubernetes, tích hợp sâu với AWS. Bạn định nghĩa một task definition (container, CPU/bộ nhớ, IAM role, port, env) và chạy nó dưới dạng một service (chạy dài hạn, có load-balance, tự động scale) hoặc một task (chạy một lần/batch). ECS chạy trên hai launch type:
| ECS on EC2 | ECS on Fargate | |
|---|---|---|
| Bạn quản lý | Fleet host EC2 (vá, scaling, dung lượng) | Không gì bên dưới task |
| Tính phí | Theo instance EC2 (trả cho cả host) | Theo vCPU/GB-giây của task |
| Tốt nhất cho | Mật độ cao, ổn định; instance GPU/đặc biệt; bin-packing để tiết kiệm | Tải biến động, đội nhỏ, không muốn lo vận hành |
| Đánh đổi | Rẻ hơn khi tận dụng cao ổn định; nhiều vận hành hơn | Không vận hành host; có thể tốn hơn ở quy mô ổn định cao |
Nguyên tắc kinh nghiệm: bắt đầu trên Fargate (không server nào phải quản lý), và chỉ chuyển sang ECS-on-EC2 khi bạn có đủ workload ổn định, dày đặc để việc sở hữu host rõ ràng có lợi, hoặc bạn cần các tính năng instance mà Fargate thiếu (GPU, loại instance cụ thể, chế độ privileged).
EKS — Elastic Kubernetes Service là Kubernetes upstream được quản lý. AWS chạy control plane (tính sẵn sàng cao, được vá); bạn chạy workload trên managed node group (EC2), Fargate profile (pod serverless), hoặc Karpenter (autoscaling node nhanh, linh hoạt). Chọn EKS khi bạn muốn hệ sinh thái Kubernetes (Helm, operator, tính di động giữa các cloud, nguồn nhân lực dồi dào) và có thể hấp thụ sự phức tạp vận hành của nó. Chọn ECS khi bạn muốn con đường đơn giản nhất và hài lòng với việc gắn với AWS. EKS mạnh hơn và di động hơn; ECS đơn giản hơn và rẻ hơn để vận hành.
App Runner là service “chỉ cần chạy container/web app của tôi”: trỏ nó vào một image trong ECR hoặc một source repo, và nó build, deploy, load-balance, kết thúc TLS, và autoscale (xuống tận zero) một web service — không có VPC, LB hay cluster nào phải cấu hình. Đây là con đường nhanh nhất từ container tới một URL HTTPS công khai, lý tưởng cho các web app và API không trạng thái nơi bạn không muốn phải nghĩ về hạ tầng. Đánh đổi là ít kiểm soát và ít núm điều chỉnh hơn ECS/EKS.
Ra quyết định trong nhóm container: App Runner cho web service đơn giản nhất → ECS/Fargate cho workload container tổng quát trên AWS → EKS khi bạn cần Kubernetes cụ thể → ECS-on-EC2 khi chi phí/kiểm soát ở mức host biện minh cho công vận hành.
Lambda — serverless functions
Lambda chạy code của bạn để phản hồi các event mà không có server nào phải quản lý, scaling tự động, và tính phí theo lượt gọi (làm tròn tới mili-giây, tính giá theo bộ nhớ×thời lượng). Bạn upload một function (zip hoặc container image tới 10 GB), chọn một runtime (Node, Python, Java, Go, .NET, Ruby, hoặc tùy chỉnh), đặt bộ nhớ (128 MB–10 GB; CPU scale theo bộ nhớ), và AWS chạy nó theo yêu cầu.
Event source — sức mạnh của Lambda nằm ở bề rộng các thứ có thể kích hoạt nó:
| Nguồn | Mẫu | Ví dụ |
|---|---|---|
| API Gateway / Function URL | Request/response đồng bộ | REST/HTTP API, webhook |
| S3 | Bất đồng bộ theo event object | Resize ảnh khi upload |
| SQS / SNS / EventBridge | Queue/pub-sub/event bus | Xử lý bất đồng bộ tách rời |
| DynamoDB / Kinesis Streams | Stream (dựa trên poll) | Change-data-capture, ETL thời gian thực |
| CloudWatch Events / Scheduler | Cron | Job theo lịch |
Concurrency là mô hình scaling và chi phí cốt lõi. Mỗi lượt gọi đồng thời là một instance function; Lambda scale theo chiều ngang bằng cách thêm instance tới giới hạn tài khoản của bạn (mặc định 1.000, có thể nâng).
- Reserved concurrency giới hạn số instance tối đa của một function (bảo vệ các database phía sau khỏi bị quá tải, và đảm bảo một mức sàn cho các function quan trọng).
- Provisioned concurrency giữ N instance ấm và đã khởi tạo sẵn — cách khắc phục độ trễ nhạy với cold-start, có tính phí.
Cold start: lượt gọi đầu tiên trên một instance mới phải trả chi phí khởi tạo (tải code, khởi động runtime, chạy init). Thường là hàng chục đến hàng trăm ms; tệ hơn với các deployment lớn, function gắn VPC (trong lịch sử), và runtime nặng (JVM/.NET). Giảm nhẹ: giữ package nhỏ, dùng provisioned concurrency cho các đường nhạy độ trễ, chọn runtime nhẹ hơn, và lazy-load các phụ thuộc nặng. Hầu hết workload bất đồng bộ đơn giản là không quan tâm tới cold start.
Layer đóng gói các phụ thuộc hoặc runtime chung tách khỏi code function — một .zip được mount vào /opt lúc runtime. Chúng giữ package function nhỏ và chia sẻ thư viện chung giữa các function, dù nhiều đội giờ ưa dùng container image cho các bộ phụ thuộc phức tạp.
Lambda là trái tim của serverless trên AWS — xem trang serverless của DevOps và tài liệu serverless của AWS để có bức tranh rộng hơn (Step Functions, EventBridge, SAM, kiến trúc hướng sự kiện).
Batch
AWS Batch chạy các job điện toán batch quy mô lớn: bạn nộp job vào các queue, định nghĩa compute environment (fleet EC2/Fargate/Spot được quản lý, scale từ zero), và Batch lên lịch, đặt chỗ và scale các container để chạy chúng, thử lại và báo cáo trong quá trình. Nó tỏa sáng cho công việc song song hồn nhiên (embarrassingly parallel) — genomics, rendering, mô phỏng Monte-Carlo, ETL — nơi bạn muốn hàng nghìn container tạm thời trên dung lượng Spot giá rẻ mà không phải tự xây scheduler. Hãy hình dung nó như “cron/queue + fleet container tự động scale, được quản lý”. Với các pipeline nặng về orchestration, hãy ghép nó với Step Functions.
Chọn compute: VM vs container vs serverless
Không có người thắng phổ quát; hãy khớp mô hình với workload.
| Chiều | EC2 (VM) | Containers (ECS/EKS) | Lambda (serverless) |
|---|---|---|---|
| Đơn vị | Cả máy | Container/pod | Function |
| Bạn quản lý | OS + runtime + scaling | Container + (có thể) host | Chỉ code |
| Scaling | ASG (phút) | Autoscaling task/pod (giây) | Tự động (ms), tới zero |
| Chi phí nhàn rỗi | Trả khi đang chạy | Trả khi đang chạy | Bằng zero khi nhàn rỗi |
| Runtime tối đa | Không giới hạn | Không giới hạn | 15 phút |
| Trạng thái | Bất kỳ | Bất kỳ (với volume) | Không trạng thái (tạm thời) |
| Tốt nhất cho | Legacy, có license, phần cứng đặc biệt, kiểm soát toàn phần | Microservice, workload di động, service ổn định | Hướng sự kiện, biến động, keo dán, API có thời gian nhàn rỗi |
Đường ra quyết định thực tế:
- Hướng sự kiện, ngắn, biến động, hoặc code keo dán? → Lambda. Chi phí nhàn rỗi bằng zero và không vận hành thắng áp đảo.
- Service chạy dài hạn, cần hệ sinh thái container hoặc lưu lượng ổn định? → Containers. Fargate trước; EKS nếu bạn cần Kubernetes; ECS-on-EC2 nếu mật độ/chi phí biện minh cho việc sở hữu host.
- App legacy, nhu cầu OS/kernel đặc biệt, phần mềm có license, GPU/HPC, hoặc kiểm soát toàn phần? → EC2.
- Job batch song song ồ ạt? → Batch (trên Spot).
Cạm bẫy phổ biến: ép một job dài hơn 15 phút vào Lambda (dùng Batch/container), chạy một API ít lưu lượng biến động trên EC2 luôn-bật (lãng phí — dùng Lambda/App Runner), hoặc dùng EKS cho ba microservice (chi phí Kubernetes mà không có lợi ích — dùng ECS/Fargate).
Ví dụ thực hành: Launch Template + Auto Scaling Group
Một web tier chịu lỗi, tự chữa lành trong Terraform — một launch template cấp cho một ASG trải khắp các AZ đằng sau một target group, scale theo CPU.
# Launch template: the recipe for each instance
resource "aws_launch_template" "web" {
name_prefix = "web-"
image_id = data.aws_ami.al2023.id # latest Amazon Linux 2023
instance_type = "t3.micro"
iam_instance_profile { name = aws_iam_instance_profile.web.name }
vpc_security_group_ids = [aws_security_group.web.id]
# Require IMDSv2 — never leave IMDSv1 open
metadata_options {
http_tokens = "required"
http_endpoint = "enabled"
}
# Bootstrap on first boot; keep it minimal — bake the rest into the AMI
user_data = base64encode(<<-EOF
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
EOF
)
tag_specifications {
resource_type = "instance"
tags = { Name = "web", Environment = "prod" }
}
}
# Auto Scaling Group: maintain a fleet across 2+ AZs, register with the LB
resource "aws_autoscaling_group" "web" {
name = "web-asg"
min_size = 2
max_size = 6
desired_capacity = 2
vpc_zone_identifier = [aws_subnet.private_a.id, aws_subnet.private_b.id]
target_group_arns = [aws_lb_target_group.web.arn]
health_check_type = "ELB" # replace instances the LB deems unhealthy
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
# Rolling replacement on template change — no downtime
instance_refresh {
strategy = "Rolling"
preferences { min_healthy_percentage = 90 }
}
tag {
key = "Name"
value = "web"
propagate_at_launch = true
}
}
# Target-tracking policy: hold average CPU at 50%
resource "aws_autoscaling_policy" "cpu" {
name = "cpu-target-50"
autoscaling_group_name = aws_autoscaling_group.web.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification { predefined_metric_type = "ASGAverageCPUUtilization" }
target_value = 50.0
}
}
Điều này mang lại cho bạn: nếu một instance chết hoặc một AZ hỏng, ASG thay thế dung lượng và ALB chỉ định tuyến tới các target khỏe mạnh — không cần con người can thiệp. Khi CPU trung bình vượt 50%, nhóm scale ra (tới 6); khi tải giảm, nó scale trở lại vào (xuống 2). Thay đổi launch template kích hoạt một lần refresh cuốn chiếu giữ 90% khỏe mạnh trong suốt quá trình. Đây là web tier “gia súc chứ không phải thú cưng” mẫu mực.
Best Practices
- Ưu tiên instance Graviton (ARM) nơi ngăn xếp của bạn hỗ trợ —
t4g/m7g/c7gthường mang lại hiệu năng/giá tốt hơn 20–40% so với x86. Test build của bạn trên ARM (hầu hết ngôn ngữ chạy được ngay) và mặc định dùng Graviton cho workload mới; chiết khấu về cơ bản là miễn phí. - Right-size không ngừng với Compute Optimizer — mục chi lớn nhất trong hầu hết hóa đơn là compute quá cỡ, tận dụng thấp. Xem xét đề xuất hằng tháng và giảm cỡ; một instance chạy ở 8% CPU là lớn hơn vài cỡ.
- Dùng Auto Scaling Group, không bao giờ dùng instance đơn lẻ, cho bất cứ thứ gì quan trọng — một instance đơn lẻ là một điểm lỗi duy nhất. Một ASG với
min ≥ 2trên ≥2 AZ tự chữa lành và sống sót qua một sự cố AZ; đó là khả năng chịu lỗi rẻ nhất bạn có thể mua. - Luôn dùng Launch Template thay vì Launch Configuration — template có phiên bản, hỗ trợ các tính năng mới nhất (mixed instances, Spot, ép buộc IMDSv2), và tích hợp với instance refresh. Launch Configuration đã bị deprecated.
- Yêu cầu IMDSv2 trên mọi instance (
http_tokens = required) — IMDSv1 đã tạo điều kiện cho nhiều vụ vi phạm SSRF-đến-đánh-cắp-credential nổi tiếng. Ép buộc nó trong launch template và trên toàn tổ chức. - Gắn IAM role vào instance, không bao giờ nhúng credential — dùng một instance profile để app nhận credential ngắn hạn, được xoay vòng từ IMDS. Key dài hạn được nướng vào user data hoặc config là bí mật bị rò rỉ kinh điển.
- Nướng golden AMI; giữ user data mỏng và idempotent — provisioning nặng lúc boot làm chậm scale-out và hỏng thất thường dưới tải. Nướng sẵn các phụ thuộc bằng Packer và để dành user data cho cấu hình chặng cuối; coi AMI là bất biến và roll forward.
- Pha Spot cho dung lượng chịu lỗi — chạy batch có thể gián đoạn, CI, và web không trạng thái trên Spot (giảm tới 90%) qua chính sách mixed-instances của ASG với nhiều loại instance để có một hồ dung lượng sâu. Luôn xử lý thông báo gián đoạn 2 phút (drain/checkpoint).
- Mặc định dùng Fargate cho container; chỉ chuyển sang EC2 khi mật độ có lợi — Fargate loại bỏ việc vá host và quản lý dung lượng. Chỉ sở hữu host khi bạn có workload ổn định, dày đặc nơi bin-packing rõ ràng tiết kiệm tiền, hoặc cần các tính năng instance mà Fargate thiếu.
- Chọn ECS cho sự đơn giản gắn với AWS, EKS chỉ khi bạn thực sự cần Kubernetes — EKS đem lại chi phí vận hành thực (nâng cấp, add-on, mạng). Chọn nó vì hệ sinh thái, tính di động và nguồn nhân lực; nếu không ECS/Fargate mang lại cùng kết quả với ít phức tạp hơn nhiều.
- Quét mọi image trong ECR và ép buộc lifecycle policy — bật scan-on-push để bắt CVE trước khi deploy, và cho hết hạn các image chưa gắn tag/cũ để registry không tích lũy rác dễ tổn thương, tốn kém.
- Chọn Lambda khi workload hướng sự kiện và bùng nổ — chi phí nhàn rỗi bằng zero và không vận hành khiến nó là mặc định cho keo dán, webhook và API biến động. Nhưng tôn trọng các giới hạn của nó: trần 15 phút, tính không trạng thái, và cold start loại nó khỏi các workload dài hoặc độ trễ phẳng.
- Thuần hóa cold start và concurrency của Lambda một cách có chủ đích — dùng provisioned concurrency cho các đường đồng bộ nhạy độ trễ, giữ package nhỏ, chọn runtime nhẹ, và đặt reserved concurrency để bảo vệ các database phía sau khỏi một cơn scaling ồ ạt.
- Khớp mô hình mua với hình dạng sử dụng — on-demand cho biến động/chưa biết, Savings Plans cho phần nền ổn định (sau 2–3 tháng dữ liệu), Spot cho phần có thể gián đoạn, Reserved cho các instance cụ thể ổn định. Đừng bao giờ cam kết một mức nền mà bạn chưa đo.
- Diệt compute nhàn rỗi và bị bỏ quên — instance đã stopped vẫn tính phí cho EBS volume của chúng, load balancer rỗng và NAT Gateway nhàn rỗi tính phí theo giờ, và các máy dev bị quên chạy suốt cuối tuần. Tự động hóa dọn dẹp và lên lịch cho non-prod dừng sau giờ làm.
- Định nghĩa mọi compute bằng Infrastructure as Code — launch template, ASG, task definition và Lambda function thuộc về Terraform/CloudFormation/CDK. Compute bấm-tay-trên-console là không thể tái lập và không thể xây lại sau một sự cố.
Tài liệu tham khảo
- roadmap.sh — DevOps Roadmap
- Amazon EC2 Documentation
- EC2 Instance Types
- AWS Graviton Processor
- Amazon Machine Images (AMIs)
- Instance Metadata Service (IMDSv2)
- Amazon EC2 Auto Scaling
- Launch Templates
- AWS Elastic Beanstalk
- Amazon ECS Documentation
- AWS Fargate
- Amazon EKS Documentation
- Amazon ECR Documentation
- AWS App Runner
- AWS Lambda Documentation
- Lambda Concurrency
- AWS Batch Documentation
- Compute Services Overview
Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.
Overview
Compute is where your code actually runs, and AWS offers a spectrum of options that trade control for convenience. At one end sits EC2 — raw virtual machines where you own the OS, the runtime, and the scaling. At the other end sits Lambda — pure functions where you own nothing but the code and AWS handles every server. In between live containers (ECS, EKS, App Runner) and managed application platforms (Elastic Beanstalk). The art of compute on AWS is not knowing every service — it is matching the workload’s shape (long-running vs bursty, stateful vs stateless, steady vs spiky) to the model that costs the least operational effort for the reliability you need.
This page walks the spectrum from VMs up to functions. It covers EC2 (instance families, AMIs, purchasing options, user data), Auto Scaling (Launch Templates and Auto Scaling Groups that turn one instance into an elastic fleet), the container stack (ECS with EC2 vs Fargate, EKS for Kubernetes, ECR for images, App Runner for the simple case), Lambda (event sources, concurrency, layers, cold starts), and Batch for large-scale batch jobs. It closes with decision guidance — when do I reach for a VM, a container, or a function? — because that first choice shapes everything downstream.
A useful framing: every compute service answers the same three questions differently — who patches the OS, who decides how many copies run, and who pays for idle time? On EC2 the answer to all three is “you.” On Fargate you stop patching hosts. On Lambda you stop paying for idle entirely. Move up the ladder only as far as the workload lets you, and no further.
Why the compute choice matters
The compute decision is the one you revisit least and pay for most. A workload built as a monolith on hand-managed EC2 accrues patching, scaling, and on-call toil every single day; the same workload as a Fargate service or a Lambda sheds most of that. But the ladder is not free to climb — Lambda imposes a 15-minute ceiling and cold-start latency, containers impose an orchestration learning curve, and serverless can cost more than a reserved VM at steady high volume. Choosing well means being honest about the workload’s real shape rather than reaching for the newest model by reflex.
Fundamentals
EC2 — Elastic Compute Cloud
EC2 provides resizable virtual machines (“instances”) launched from an image (AMI) onto a chosen instance type, inside a VPC subnet, with attached storage and a security group. It is the oldest and most flexible AWS compute service and the substrate under many others (EKS nodes, ECS on EC2, EMR, and more run on it).
Instance families group hardware by workload profile. The name encodes the family, generation, and size — e.g. m7g.xlarge is family m, generation 7, the g (Graviton/ARM) variant, at xlarge size.
| Family | Optimized for | Examples | Typical use |
|---|---|---|---|
| T (burstable) | Baseline CPU + burst credits | t3, t4g | Dev boxes, low-traffic web, microservices with idle time |
| M (general) | Balanced CPU:memory (≈1:4) | m6i, m7g | Web/app servers, small databases, most workloads |
| C (compute) | High CPU:memory | c6i, c7g | Batch, encoding, HPC, game servers, high-throughput APIs |
| R (memory) | High memory (≈1:8) | r6i, r7g | In-memory caches, large databases, analytics |
| X / u (high memory) | Extreme memory (TBs) | x2idn, u-6tb1 | SAP HANA, huge in-memory DBs |
| I / D (storage) | Local NVMe/HDD throughput | i4i, d3 | NoSQL, data warehouses, distributed file systems |
| P / G / Inf / Trn (accelerated) | GPU / ML accelerators | p5, g5, inf2, trn1 | Training, inference, graphics, ML |
Graviton (ARM): the g-suffixed instances (m7g, c7g, t4g) run AWS’s own ARM chips and typically deliver ~20–40% better price/performance than x86 equivalents. If your stack builds cleanly for ARM (most interpreted/JIT languages and modern compiled ones do), Graviton is often the easy win.
AMIs (Amazon Machine Images) are the templates instances boot from — a snapshot of a root volume plus metadata (architecture, virtualization type, block-device mapping). They come as AWS-provided (Amazon Linux 2023, Ubuntu, Windows), Marketplace, or your own golden images baked with tools like Packer. Baking dependencies into an AMI (“immutable infrastructure”) makes launches fast and deterministic; the alternative is provisioning at boot (see user data).
User data is a script (shell or cloud-init) passed at launch and run once on first boot — the bootstrapping hook for installing packages, pulling config, or registering with a cluster. Keep it small and idempotent; heavy user-data scripts slow launches and are a common source of “works on relaunch, fails on scale-out” bugs. Bake heavy setup into the AMI instead.
Instance metadata service (IMDS): every instance can query http://169.254.169.254/ for its own metadata (instance ID, region, IAM role credentials). Always require IMDSv2 (token-based) — IMDSv1 was the vector in several high-profile SSRF-to-credential-theft breaches.
Purchasing options (also covered on the Overview page):
| Option | Discount | Commitment | Use for |
|---|---|---|---|
| On-Demand | 0% (baseline) | None | Spiky, short-lived, unpredictable |
| Savings Plans | up to ~72% | 1/3 yr $/hr | Steady baseline compute |
| Reserved Instances | up to ~72% | 1/3 yr, specific type | Stable, predictable usage |
| Spot | up to ~90% | None (2-min reclaim notice) | Fault-tolerant, interruptible |
| Dedicated Hosts | premium | Optional | BYOL licensing, physical isolation |
Auto Scaling Groups and Launch Templates
A single instance is a pet with a single point of failure. An Auto Scaling Group (ASG) turns it into cattle: a managed fleet that maintains a target count, replaces unhealthy instances, and grows or shrinks with demand across multiple AZs.
- Launch Template — the recipe for an instance: AMI, instance type(s), key pair, security groups, IAM instance profile, user data, block devices. Templates are versioned (Launch Configurations, the older form, are not — always use templates).
- Desired / min / max capacity — the ASG keeps
desiredinstances running, never fewer thanminor more thanmax. - Health checks — EC2 status checks and/or ELB health checks; a failing instance is terminated and replaced automatically.
- Scaling policies — target tracking (keep average CPU at 50%), step scaling (add N when a CloudWatch alarm fires), scheduled (scale up before business hours), or predictive (ML-forecast demand).
- Multi-AZ — supply subnets in ≥2 AZs and the ASG balances instances across them, so one AZ failure loses only a fraction of capacity.
ASGs pair with an Application Load Balancer (ALB) or Network Load Balancer (NLB): the ASG registers new instances with a target group, the LB stops routing to draining ones, and rolling replacements happen with no downtime. This is the classic resilient web-tier pattern.
Elastic Beanstalk
Elastic Beanstalk is a PaaS layer over EC2, ASG, ELB, and CloudWatch: you hand it code (a JAR, a container, a zip) plus a platform (Java, Node, Python, .NET, Docker) and it provisions and manages the underlying stack for you, including rolling deploys and health dashboards. It is a fast on-ramp for teams that want “just deploy my app” without wiring the primitives by hand — but you retain access to the resources it creates. In modern practice it has largely been superseded by containers (ECS/App Runner) and IaC, but it remains a reasonable choice for simple web apps and for lifting a legacy app onto AWS with minimal rework.
Key Concepts
Containers on AWS
Containers package an app with its dependencies into a portable image. AWS offers a full stack around them:
ECR — Elastic Container Registry is the managed private image registry. Push images with docker push, scan them for CVEs on push, apply lifecycle policies to expire old tags, and pull them into ECS/EKS/Lambda. It is the default home for your images.
ECS — Elastic Container Service is AWS’s own container orchestrator — simpler than Kubernetes, deeply integrated with AWS. You define a task definition (containers, CPU/memory, IAM role, ports, env) and run it as a service (long-running, load-balanced, auto-scaled) or a task (one-off/batch). ECS runs on two launch types:
| ECS on EC2 | ECS on Fargate | |
|---|---|---|
| You manage | The EC2 host fleet (patching, scaling, capacity) | Nothing below the task |
| Billing | Per EC2 instance (pay for whole hosts) | Per task vCPU/GB-second |
| Best for | High, steady density; GPU/special instances; bin-packing for cost | Variable load, small teams, no ops appetite |
| Trade-off | Cheaper at high steady utilization; more ops | Zero host ops; can cost more at high steady scale |
The rule of thumb: start on Fargate (no servers to manage), and move to ECS-on-EC2 only when you have enough steady, dense workload that owning the hosts clearly pays off, or you need instance features Fargate lacks (GPUs, specific instance types, privileged mode).
EKS — Elastic Kubernetes Service is managed upstream Kubernetes. AWS runs the control plane (highly available, patched); you run workloads on managed node groups (EC2), Fargate profiles (serverless pods), or Karpenter (fast, flexible autoscaling of nodes). Choose EKS when you want the Kubernetes ecosystem (Helm, operators, portability across clouds, a large talent pool) and can absorb its operational complexity. Choose ECS when you want the simplest path and are happy to be AWS-native. EKS is more powerful and more portable; ECS is simpler and cheaper to operate.
App Runner is the “just run my container/web app” service: point it at an image in ECR or a source repo, and it builds, deploys, load-balances, TLS-terminates, and autoscales (down to zero) a web service — no VPC, LB, or cluster to configure. It is the fastest path from container to public HTTPS URL, ideal for stateless web apps and APIs where you don’t want to think about infrastructure. The trade-off is less control and fewer knobs than ECS/EKS.
Decision within containers: App Runner for the simplest web service → ECS/Fargate for general container workloads on AWS → EKS when you need Kubernetes specifically → ECS-on-EC2 when host-level cost/control justifies the ops.
Lambda — serverless functions
Lambda runs your code in response to events with no servers to manage, automatic scaling, and pay-per-invocation billing (rounded to the millisecond, priced by memory×duration). You upload a function (zip or container image up to 10 GB), pick a runtime (Node, Python, Java, Go, .NET, Ruby, or custom), set memory (128 MB–10 GB; CPU scales with memory), and AWS runs it on demand.
Event sources — Lambda’s power is the breadth of things that can trigger it:
| Source | Pattern | Example |
|---|---|---|
| API Gateway / Function URL | Synchronous request/response | REST/HTTP APIs, webhooks |
| S3 | Async on object events | Resize image on upload |
| SQS / SNS / EventBridge | Queue/pub-sub/event bus | Decoupled async processing |
| DynamoDB / Kinesis Streams | Stream (poll-based) | Change-data-capture, real-time ETL |
| CloudWatch Events / Scheduler | Cron | Scheduled jobs |
Concurrency is the core scaling and cost model. Each concurrent invocation is one function instance; Lambda scales horizontally by adding instances up to your account limit (default 1,000, raisable).
- Reserved concurrency caps a function’s max instances (protects downstream databases from being overwhelmed, and guarantees a floor for critical functions).
- Provisioned concurrency keeps N instances warm and initialized — the fix for cold-start-sensitive latency at a cost.
Cold starts: the first invocation on a new instance pays initialization cost (download code, start runtime, run init). Typically tens to hundreds of ms; worse for large deployments, VPC-attached functions (historically), and heavy runtimes (JVM/.NET). Mitigations: keep packages small, use provisioned concurrency for latency-critical paths, choose lighter runtimes, and lazy-load heavy dependencies. Most async workloads simply don’t care about cold starts.
Layers package shared dependencies or runtimes separately from function code — a .zip mounted into /opt at runtime. They keep function packages small and share common libraries across functions, though many teams now prefer container images for complex dependency sets.
Lambda is the heart of serverless on AWS — see the DevOps serverless page and the AWS serverless material for the broader picture (Step Functions, EventBridge, SAM, event-driven architecture).
Batch
AWS Batch runs large-scale batch computing jobs: you submit jobs to queues, define compute environments (managed EC2/Fargate/Spot fleets that scale from zero), and Batch schedules, places, and scales the containers to run them, retrying and reporting as it goes. It shines for embarrassingly parallel work — genomics, rendering, Monte-Carlo simulation, ETL — where you want thousands of transient containers on cheap Spot capacity without building a scheduler yourself. Think of it as “cron/queue + autoscaling container fleet, managed.” For orchestration-heavy pipelines, pair it with Step Functions.
Choosing compute: VM vs container vs serverless
There is no universal winner; match the model to the workload.
| Dimension | EC2 (VM) | Containers (ECS/EKS) | Lambda (serverless) |
|---|---|---|---|
| Unit | Whole machine | Container/pod | Function |
| You manage | OS + runtime + scaling | Container + (maybe) hosts | Only code |
| Scaling | ASG (minutes) | Task/pod autoscaling (seconds) | Automatic (ms), to zero |
| Idle cost | Pay while running | Pay while running | Zero when idle |
| Max runtime | Unlimited | Unlimited | 15 minutes |
| State | Any | Any (with volumes) | Stateless (ephemeral) |
| Best for | Legacy, licensed, special hardware, full control | Microservices, portable workloads, steady services | Event-driven, spiky, glue, APIs with idle time |
Practical decision path:
- Event-driven, short, spiky, or glue code? → Lambda. Zero idle cost and zero ops win decisively.
- Long-running service, needs a container ecosystem or steady traffic? → Containers. Fargate first; EKS if you need Kubernetes; ECS-on-EC2 if density/cost justifies hosts.
- Legacy app, special OS/kernel needs, licensed software, GPU/HPC, or full control? → EC2.
- Massively parallel batch jobs? → Batch (on Spot).
Common pitfalls: forcing a 15-minute+ job into Lambda (use Batch/containers), running a spiky low-traffic API on always-on EC2 (waste — use Lambda/App Runner), or adopting EKS for three microservices (Kubernetes overhead without the benefit — use ECS/Fargate).
Worked example: Launch Template + Auto Scaling Group
A resilient, self-healing web tier in Terraform — a launch template feeding an ASG spread across AZs behind a target group, scaling on CPU.
# Launch template: the recipe for each instance
resource "aws_launch_template" "web" {
name_prefix = "web-"
image_id = data.aws_ami.al2023.id # latest Amazon Linux 2023
instance_type = "t3.micro"
iam_instance_profile { name = aws_iam_instance_profile.web.name }
vpc_security_group_ids = [aws_security_group.web.id]
# Require IMDSv2 — never leave IMDSv1 open
metadata_options {
http_tokens = "required"
http_endpoint = "enabled"
}
# Bootstrap on first boot; keep it minimal — bake the rest into the AMI
user_data = base64encode(<<-EOF
#!/bin/bash
dnf install -y nginx
systemctl enable --now nginx
EOF
)
tag_specifications {
resource_type = "instance"
tags = { Name = "web", Environment = "prod" }
}
}
# Auto Scaling Group: maintain a fleet across 2+ AZs, register with the LB
resource "aws_autoscaling_group" "web" {
name = "web-asg"
min_size = 2
max_size = 6
desired_capacity = 2
vpc_zone_identifier = [aws_subnet.private_a.id, aws_subnet.private_b.id]
target_group_arns = [aws_lb_target_group.web.arn]
health_check_type = "ELB" # replace instances the LB deems unhealthy
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
# Rolling replacement on template change — no downtime
instance_refresh {
strategy = "Rolling"
preferences { min_healthy_percentage = 90 }
}
tag {
key = "Name"
value = "web"
propagate_at_launch = true
}
}
# Target-tracking policy: hold average CPU at 50%
resource "aws_autoscaling_policy" "cpu" {
name = "cpu-target-50"
autoscaling_group_name = aws_autoscaling_group.web.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification { predefined_metric_type = "ASGAverageCPUUtilization" }
target_value = 50.0
}
}
What this buys you: if an instance dies or an AZ fails, the ASG replaces capacity and the ALB routes only to healthy targets — with no human in the loop. When average CPU crosses 50%, the group scales out (up to 6); when load falls, it scales back in (down to 2). Changing the launch template triggers a rolling refresh keeping 90% healthy throughout. This is the canonical “cattle not pets” web tier.
Best Practices
- Prefer Graviton (ARM) instances where your stack supports them —
t4g/m7g/c7gtypically deliver 20–40% better price/performance than x86. Test your build on ARM (most languages just work) and default to Graviton for new workloads; the discount is essentially free. - Right-size relentlessly with Compute Optimizer — the largest line item in most bills is oversized, under-utilized compute. Review recommendations monthly and downsize; an instance sitting at 8% CPU is several sizes too big.
- Use Auto Scaling Groups, never lone instances, for anything that matters — a single instance is a single point of failure. An ASG with
min ≥ 2across ≥2 AZs self-heals and survives an AZ outage; it is the cheapest resilience you can buy. - Always use Launch Templates over Launch Configurations — templates are versioned, support the newest features (mixed instances, Spot, IMDSv2 enforcement), and integrate with instance refresh. Launch Configurations are deprecated.
- Require IMDSv2 on every instance (
http_tokens = required) — IMDSv1 enabled several high-profile SSRF-to-credential-theft breaches. Enforce it in launch templates and org-wide. - Attach IAM roles to instances, never embed credentials — use an instance profile so the app gets short-lived, rotated credentials from IMDS. Long-lived keys baked into user data or config are the classic leaked secret.
- Bake golden AMIs; keep user data thin and idempotent — heavy boot-time provisioning slows scale-out and fails intermittently under load. Pre-bake dependencies with Packer and reserve user data for last-mile config; treat AMIs as immutable and roll forward.
- Blend Spot for fault-tolerant capacity — run interruptible batch, CI, and stateless web on Spot (up to 90% off) via ASG mixed-instances policies with multiple instance types for a deep capacity pool. Always handle the 2-minute interruption notice (drain/checkpoint).
- Default containers to Fargate; move to EC2 only when density pays off — Fargate removes host patching and capacity management. Own the hosts only when you have steady, dense workloads where bin-packing clearly saves money, or need instance features Fargate lacks.
- Choose ECS for AWS-native simplicity, EKS only when you truly need Kubernetes — EKS brings real operational overhead (upgrades, add-ons, networking). Adopt it for the ecosystem, portability, and talent pool; otherwise ECS/Fargate delivers the same outcome with far less complexity.
- Scan every image in ECR and enforce lifecycle policies — enable scan-on-push to catch CVEs before deploy, and expire untagged/old images so the registry doesn’t accumulate vulnerable, costly cruft.
- Reach for Lambda when the workload is event-driven and bursty — zero idle cost and zero ops make it the default for glue, webhooks, and spiky APIs. But respect its limits: the 15-minute ceiling, statelessness, and cold starts rule it out for long or latency-flat workloads.
- Tame Lambda cold starts and concurrency deliberately — use provisioned concurrency for latency-critical synchronous paths, keep packages small, pick light runtimes, and set reserved concurrency to protect downstream databases from a scaling stampede.
- Match the purchasing model to the usage shape — on-demand for spiky/unknown, Savings Plans for the steady baseline (after 2–3 months of data), Spot for interruptible, Reserved for stable specific instances. Never commit to a baseline you haven’t measured.
- Kill idle and orphaned compute — stopped instances still bill for their EBS volumes, empty load balancers and idle NAT Gateways charge hourly, and forgotten dev boxes run all weekend. Automate cleanup and schedule non-prod to stop after hours.
- Define all compute in Infrastructure as Code — launch templates, ASGs, task definitions, and Lambda functions belong in Terraform/CloudFormation/CDK. Console-clicked compute is unreproducible and impossible to rebuild after an outage.
References
- roadmap.sh — DevOps Roadmap
- Amazon EC2 Documentation
- EC2 Instance Types
- AWS Graviton Processor
- Amazon Machine Images (AMIs)
- Instance Metadata Service (IMDSv2)
- Amazon EC2 Auto Scaling
- Launch Templates
- AWS Elastic Beanstalk
- Amazon ECS Documentation
- AWS Fargate
- Amazon EKS Documentation
- Amazon ECR Documentation
- AWS App Runner
- AWS Lambda Documentation
- Lambda Concurrency
- AWS Batch Documentation
- Compute Services Overview