Cloud cost incident runbook là quy trình giúp đội System Administrator, DevOps và Cloud Engineer phản ứng có phương pháp khi hóa đơn cloud tăng bất thường. Trong production, sự cố chi phí không chỉ là chuyện kế toán: nó có thể báo hiệu autoscaling mất kiểm soát, log đẩy quá nhiều, snapshot bị bỏ quên, tài khoản bị lộ khóa truy cập, hoặc một thay đổi hạ tầng chưa được gắn giới hạn.
Bài này đi theo hướng thực chiến: giả lập một ca trực khi chi phí tăng 300% sau một đêm, cách khoanh vùng nguyên nhân, lệnh kiểm tra mẫu, cách đặt guardrail để sự cố không lặp lại, và checklist nghiệm thu trước khi đóng incident.
Bối cảnh production: khi hóa đơn cloud trở thành incident
Giả sử hệ thống thương mại điện tử chạy trên cloud có các thành phần sau:
- Compute: VM/EC2, managed Kubernetes hoặc autoscaling group.
- Database: managed PostgreSQL/MySQL, backup tự động, snapshot theo lịch.
- Storage: object storage cho ảnh, log, artifact CI/CD.
- Network: load balancer, NAT gateway, CDN, egress ra Internet.
- Observability: log tập trung, metric, tracing.
Đêm qua, dashboard billing báo chi phí ngày tăng từ 120 USD lên 480 USD. Nếu chỉ nhìn tổng tiền, bạn chưa biết phải tắt gì. Mục tiêu của runbook là trả lời nhanh bốn câu hỏi:
- Dịch vụ nào tăng?
- Region/account/project nào tăng?
- Thay đổi nào xảy ra trước thời điểm tăng?
- Cần chặn tạm ở đâu mà không làm sập production?
Nguyên tắc phản ứng: đừng tắt bừa, hãy cô lập theo lớp
Một lỗi phổ biến là thấy hóa đơn tăng thì tắt instance lớn nhất. Cách này nguy hiểm vì instance đó có thể là node database hoặc worker đang xử lý đơn hàng. Thay vào đó, hãy cô lập theo lớp:
- Billing layer: xác định dịch vụ, region, tag, account.
- Change layer: truy vết deploy, IaC apply, job batch, thay đổi autoscaling.
- Runtime layer: kiểm tra metric tài nguyên, request, queue, log volume.
- Security layer: rà access key, API call bất thường, resource lạ.
- Control layer: đặt budget, quota, policy, lifecycle, TTL.
Bước 1: lấy ảnh chụp chi phí theo dịch vụ và thời gian
Với AWS, bạn có thể dùng Cost Explorer để xem chi phí theo ngày và theo service. Ví dụ:
aws ce get-cost-and-usage --time-period Start=2026-07-01,End=2026-07-03 --granularity DAILY --metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICE --output table
Output mẫu:
-----------------------------------------------
| GetCostAndUsage |
+----------------------+----------------------+
| Amazon Elastic Compute Cloud - Compute | 260.42 USD |
| EC2 - Other | 91.20 USD |
| AmazonCloudWatch | 78.63 USD |
| Amazon S3 | 31.10 USD |
+----------------------+----------------------+
Ở ví dụ này, ba hướng điều tra nổi bật là compute, EC2-Other và CloudWatch. EC2-Other thường bao gồm EBS, snapshot, NAT gateway, data transfer hoặc Elastic IP. CloudWatch tăng có thể do log ingestion quá lớn.
GCP và Azure tương đương
Trên GCP, dùng Billing Export sang BigQuery để truy vấn:
SELECT
service.description AS service,
project.id AS project_id,
SUM(cost) AS total_cost
FROM `billing.gcp_billing_export_v1_*`
WHERE usage_start_time >= TIMESTAMP('2026-07-01')
GROUP BY service, project_id
ORDER BY total_cost DESC
LIMIT 20;
Trên Azure, dùng Cost Management hoặc CLI:
az costmanagement query --type Usage --timeframe MonthToDate --dataset '{"granularity":"Daily","aggregation":{"totalCost":{"name":"PreTaxCost","function":"Sum"}},"grouping":[{"type":"Dimension","name":"ServiceName"}]}'
Bước 2: drill-down theo tag, account, project và region
Nếu tổ chức có tagging tốt, chi phí sẽ chỉ thẳng team hoặc workload gây tăng. Với AWS:
aws ce get-cost-and-usage --time-period Start=2026-07-01,End=2026-07-03 --granularity DAILY --metrics UnblendedCost --group-by Type=TAG,Key=Environment Type=DIMENSION,Key=REGION
Nếu kết quả có nhiều dòng No tag key, đó là một phát hiện quan trọng. Không có tag nghĩa là đội vận hành mất khả năng quy trách nhiệm và tối ưu chi phí. Trong incident report, hãy ghi rõ: “resource thiếu tag làm tăng MTTR”.
Bước 3: kiểm tra compute và autoscaling
Compute thường là nguồn tăng chi phí dễ hiểu nhất: instance bị scale quá mức, node Kubernetes không scale down, job batch tạo máy rồi quên xóa.
aws ec2 describe-instances --filters Name=instance-state-name,Values=running --query 'Reservations[].Instances[].{Id:InstanceId,Type:InstanceType,AZ:Placement.AvailabilityZone,Launch:LaunchTime,Name:Tags[?Key==`Name`]|[0].Value}' --output table
Điểm cần nhìn:
- Instance mới tạo gần thời điểm chi phí tăng.
- Instance type lớn bất thường như m6i.4xlarge, r6i.8xlarge, GPU.
- Instance không có tag owner/environment.
- Instance chạy ở region lạ.
Với Kubernetes, kiểm tra node và pod request:
kubectl get nodes -o wide
kubectl top nodes
kubectl get pods -A --sort-by=.spec.nodeName
kubectl get hpa -A
kubectl describe hpa -A
Nếu HPA scale lên vì CPU cao, cần xác định CPU cao là traffic thật, bug vòng lặp, hay request limit đặt sai. Nếu cluster autoscaler không scale down, kiểm tra PodDisruptionBudget, pod dùng local storage, hoặc node có taint/toleration đặc biệt.
Bước 4: điều tra NAT gateway, egress và data transfer
NAT gateway và egress là “sát thủ thầm lặng” trong cloud bill. Một job backup đẩy dữ liệu qua Internet thay vì private endpoint có thể tạo chi phí lớn.
aws cloudwatch get-metric-statistics --namespace AWS/NATGateway --metric-name BytesOutToDestination --dimensions Name=NatGatewayId,Value=nat-xxxxxxxx --start-time 2026-07-01T00:00:00Z --end-time 2026-07-03T00:00:00Z --period 3600 --statistics Sum
Nếu byte out tăng mạnh, tiếp tục kiểm tra VPC Flow Logs:
fields @timestamp, srcAddr, dstAddr, bytes
| filter action = 'ACCEPT'
| stats sum(bytes) as totalBytes by srcAddr, dstAddr
| sort totalBytes desc
| limit 20
Cách xử lý thường gặp:
- Dùng VPC endpoint/private endpoint cho S3, ECR, CloudWatch, Storage Account.
- Đưa batch job vào cùng region với dữ liệu.
- Không kéo full backup qua NAT nếu có snapshot/native replication.
- Đặt alert riêng cho NAT bytes và data transfer.
Bước 5: kiểm tra log ingestion và retention
CloudWatch, Azure Monitor hoặc GCP Cloud Logging có thể tăng đột biến khi ứng dụng log lỗi liên tục. Kiểm tra log group lớn nhất:
aws logs describe-log-groups --query 'logGroups[].{Name:logGroupName,Bytes:storedBytes,Retention:retentionInDays}' --output json | jq 'sort_by(.Bytes) | reverse | .[:20]'
Nếu thấy retention rỗng, nghĩa là log giữ vô hạn. Với production, retention nên được phân tầng:
- Hot troubleshooting: 7-14 ngày.
- Compliance/security: chuyển sang storage rẻ hơn.
- Debug log: không bật mặc định trên production.
aws logs put-retention-policy --log-group-name /prod/app/api --retention-in-days 14
Bước 6: rà snapshot, volume và object storage
Snapshot và object lifecycle bị quên là nguyên nhân kinh điển. Kiểm tra EBS volume không gắn:
aws ec2 describe-volumes --filters Name=status,Values=available --query 'Volumes[].{Id:VolumeId,Size:Size,Type:VolumeType,Create:CreateTime,Name:Tags[?Key==`Name`]|[0].Value}' --output table
Kiểm tra snapshot cũ:
aws ec2 describe-snapshots --owner-ids self --query 'Snapshots[].{Id:SnapshotId,Size:VolumeSize,Start:StartTime,Desc:Description}' --output table
Không xóa ngay snapshot khi chưa xác định chain backup và RPO. Hãy đánh dấu candidate, xác nhận owner, rồi chuyển sang policy lifecycle.
Bước 7: kiểm tra dấu hiệu lộ khóa hoặc resource lạ
Nếu chi phí tăng ở region bạn không dùng, hoặc xuất hiện GPU/crypto-like workload, ưu tiên hướng security. Với AWS CloudTrail:
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=RunInstances --start-time 2026-07-01T00:00:00Z --end-time 2026-07-03T00:00:00Z --query 'Events[].{Time:EventTime,User:Username,Event:EventName,Resource:Resources}'
Checklist security nhanh:
- Vô hiệu hóa access key nghi ngờ, nhưng phối hợp để tránh làm sập pipeline.
- Kiểm tra user/role tạo resource.
- Kiểm tra region không nằm trong danh sách cho phép.
- Bật MFA và SCP/policy giới hạn instance family nếu dùng multi-account.
Bước 8: biện pháp chặn tạm an toàn
Khi đã khoanh vùng, chọn biện pháp ít rủi ro nhất:
- Giảm max size autoscaling group thay vì terminate thủ công toàn bộ node.
- Giảm log level từ debug về info/warn.
- Đặt retention log ngắn hơn.
- Tạm dừng batch job không critical.
- Thêm lifecycle rule cho object mới, chưa xóa dữ liệu cũ nếu chưa duyệt.
- Chặn region bằng policy nếu chắc chắn không dùng.
Guardrail lâu dài: budget, anomaly detection, quota và policy
Sau incident, phải chuyển từ phản ứng thủ công sang guardrail tự động.
Budget và cảnh báo
aws budgets create-budget --account-id 123456789012 --budget '{
"BudgetName":"prod-monthly-budget",
"BudgetLimit":{"Amount":"3000","Unit":"USD"},
"TimeUnit":"MONTHLY",
"BudgetType":"COST"
}'
Budget không tự cứu hệ thống nếu chỉ gửi email cho một người. Nên gửi về Slack/Teams, ticketing và on-call.
Tag policy bắt buộc
Tối thiểu cần các tag:
Environment: prod, staging, dev.Owner: team hoặc email nhóm.CostCenter: mã chi phí.Service: tên workload.TTL: cho tài nguyên lab/tạm.
Quota và giới hạn region
Không phải workload nào cũng cần mọi region và mọi instance family. Giới hạn sớm giúp giảm blast radius khi có lỗi automation hoặc credential leak.
Lỗi thường gặp khi xử lý cloud cost incident
- Chỉ nhìn monthly bill: quá chậm, cần daily/hourly trend.
- Không có tag: không truy được owner, mất thời gian họp.
- Tắt resource không hiểu dependency: tiết kiệm vài USD nhưng gây downtime.
- Không kiểm tra egress: compute không tăng nhưng data transfer tăng vẫn rất đắt.
- Không đóng vòng feedback: xử lý xong nhưng không tạo policy, tháng sau lặp lại.
Checklist nghiệm thu trước khi đóng incident
- Đã xác định service, account/project, region gây tăng chi phí.
- Đã liên kết được với deploy, job, thay đổi config hoặc dấu hiệu security.
- Đã áp dụng biện pháp chặn tạm không gây downtime.
- Đã tạo ticket cleanup cho resource thừa: volume, snapshot, bucket, IP, load balancer.
- Đã cấu hình budget/anomaly alert tới kênh on-call.
- Đã bổ sung tag policy hoặc IaC validation.
- Đã ghi postmortem: timeline, root cause, cost impact, action items.
Lab thực hành: dựng dashboard cost tối thiểu
Bài tập cho môi trường lab:
- Tạo một project/account sandbox có budget nhỏ.
- Tạo 3 resource có tag đầy đủ và 1 resource thiếu tag.
- Bật billing export hoặc Cost Explorer report.
- Tạo truy vấn top service theo ngày.
- Tạo cảnh báo khi chi phí daily vượt ngưỡng.
- Viết policy hoặc script phát hiện resource thiếu tag.
Ví dụ script kiểm tra EC2 thiếu tag Owner:
aws ec2 describe-instances --query 'Reservations[].Instances[?!not_null(Tags[?Key==`Owner`].Value)][] .{Id:InstanceId,Type:InstanceType,State:State.Name}' --output table
Trong production thật, script này nên chạy bằng read-only role, xuất kết quả về ticket hoặc dashboard thay vì tự động xóa.
Kết luận
Một Cloud cost incident runbook tốt giúp đội vận hành chuyển từ “hóa đơn tăng rồi hoảng” sang quy trình có dữ liệu: xác định dịch vụ, khoanh vùng resource, kiểm tra thay đổi, chặn tạm an toàn, rồi đặt guardrail lâu dài. Cloud linh hoạt, nhưng không có ngân sách, tag, quota và observability thì sự linh hoạt đó rất dễ biến thành chi phí khó kiểm soát.
