Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn đang vận hành hệ thống backend cho một sàn thương mại điện tử ở Việt Nam. Ngày thường traffic bình bình, nhưng cứ đến khung "sale 12h12" hay "flash sale 20h" thì lượng người dùng tăng gấp 10–20 lần chỉ trong vài phút. Nếu bạn cấu hình cố định số lượng container (Pod), bạn rơi vào một trong hai cái bẫy: hoặc để dư thật nhiều Pod chạy 24/7 và đốt tiền cloud vô ích, hoặc để vừa đủ rồi hệ thống sập ngay khi cao điểm. Cả hai đều tệ.
Autoscaling — tự động co giãn — chính là lời giải cho bài toán này. Nó là một trong những lý do quan trọng nhất khiến các công ty chọn Kubernetes thay vì tự quản lý server thủ công. Kubernetes cho phép hệ thống tự nhìn vào chính mình, nhận ra "à, tôi đang quá tải" hoặc "tôi đang dư thừa", rồi tự điều chỉnh.
Nhưng ở đây có một cái bẫy tư duy phổ biến: nhiều bạn mới nghĩ autoscaling chỉ là "thêm bớt Pod". Thực ra Kubernetes có ba tầng autoscaling khác nhau, giải quyết ba bài toán khác nhau, và một hệ thống production tốt thường phải phối hợp cả ba. Hiểu rõ từng tầng — nó co giãn cái gì, dựa vào tín hiệu gì, và khi nào thì mâu thuẫn nhau — là kỹ năng phân biệt một DevOps engineer thực thụ với người chỉ biết copy YAML trên mạng. Bài này sẽ giúp bạn nắm chắc điều đó.
Khái niệm cốt lõi
Trước khi đi vào ba tầng, bạn cần nhớ một nền tảng: mọi autoscaling trong Kubernetes đều phụ thuộc vào việc bạn đã khai báo resource requests và limits cho container. Nếu bạn không khai báo requests.cpu và requests.memory, thì phần lớn cơ chế autoscaling sẽ không có dữ liệu để ra quyết định. Đây là lỗi số một của người mới, chúng ta sẽ nhắc lại ở phần sau.
Ba tầng autoscaling là:
1. HPA — Horizontal Pod Autoscaler (co giãn theo chiều ngang)
HPA điều chỉnh số lượng replica (số bản sao Pod) của một Deployment, ReplicaSet hoặc StatefulSet. "Horizontal" nghĩa là scale ra rộng: khi tải cao, HPA tăng từ 3 Pod lên 10 Pod; khi tải giảm, nó rút xuống lại.
Cách hoạt động: HPA chạy một vòng lặp kiểm soát (control loop), mặc định cứ 15 giây một lần, đọc chỉ số (metric) hiện tại của các Pod — thường là CPU utilization trung bình — rồi so với ngưỡng mục tiêu bạn đặt. Công thức đơn giản hoá:
desiredReplicas = ceil( currentReplicas × (currentMetric / targetMetric) )
Ví dụ bạn đặt target CPU = 50%, hiện đang chạy 4 Pod với CPU trung bình 100%. Thì 4 × (100/50) = 8 → HPA scale lên 8 Pod. HPA lấy metric qua Metrics Server (cho CPU/RAM cơ bản) hoặc qua custom/external metrics (ví dụ số lượng message trong hàng đợi RabbitMQ, số request per second qua Prometheus Adapter).
HPA phù hợp nhất với ứng dụng stateless có thể chạy nhiều bản song song: web server, API service, worker xử lý job. Đây là tầng autoscaling được dùng nhiều nhất và nên là lựa chọn đầu tiên của bạn.
2. VPA — Vertical Pod Autoscaler (co giãn theo chiều dọc)
VPA không đổi số lượng Pod, mà đổi kích thước của mỗi Pod — tức là điều chỉnh requests và limits về CPU/RAM cho phù hợp với nhu cầu thực tế. "Vertical" nghĩa là làm cho từng Pod "to hơn" hoặc "nhỏ hơn".
VPA quan sát mức tiêu thụ tài nguyên thực tế của workload theo thời gian (dùng lịch sử metric), rồi đề xuất giá trị request tối ưu. Nó có ba chế độ chính:
- Off (recommendation only): chỉ đưa ra khuyến nghị, không tự thay đổi. Rất hợp để bạn "đo đạc" xem nên đặt request bao nhiêu — dùng con số này rồi tự cập nhật thủ công.
- Auto / Recreate: VPA tự cập nhật request và khởi động lại Pod để áp dụng giá trị mới. Lưu ý điểm này: cho tới các phiên bản phổ biến hiện nay, thay đổi request thường yêu cầu recreate Pod, gây gián đoạn ngắn.
Cảnh báo quan trọng: KHÔNG dùng VPA (chế độ Auto) và HPA cùng lúc trên cùng một metric (ví dụ cùng dựa trên CPU). Chúng sẽ đánh nhau: HPA muốn thêm Pod khi CPU cao, VPA lại muốn tăng request CPU của từng Pod — hai bên phản ứng chồng chéo gây dao động (thrashing). Nếu muốn kết hợp, hãy để HPA scale theo một metric (ví dụ CPU hoặc custom metric), còn VPA chỉ quản RAM, hoặc VPA chỉ chạy ở chế độ recommendation.
3. Cluster Autoscaler (co giãn số lượng Node)
Hai tầng trên co giãn Pod, nhưng Pod phải chạy trên Node (máy chủ vật lý/ảo). Nếu HPA muốn tạo thêm 5 Pod mà cluster không còn chỗ trống trên Node nào, thì các Pod đó rơi vào trạng thái Pending — treo mãi không chạy được. Đây là lúc Cluster Autoscaler (CA) vào cuộc.
CA quan sát: có Pod nào đang Pending vì thiếu tài nguyên không? Nếu có, nó gọi API của cloud provider (AWS EKS, Google GKE, Azure AKS...) để thêm Node mới vào node group. Ngược lại, nếu có Node đang trống hoặc dùng rất ít mà các Pod trên đó có thể dồn sang Node khác, CA sẽ rút Node đó ra để tiết kiệm tiền.
Một biến thể hiện đại rất đáng nhắc là Karpenter (của AWS, mã nguồn mở) — thay vì làm việc với các node group cố định, Karpenter chọn đúng loại máy phù hợp nhất cho tập Pod đang pending, cấp phát nhanh hơn và tối ưu chi phí tốt hơn. Nhiều công ty ở Đông Nam Á đang chuyển từ Cluster Autoscaler cổ điển sang Karpenter vì lý do này.
Điểm mấu chốt để nhớ về quan hệ ba tầng: HPA/VPA quyết định cần bao nhiêu Pod và Pod to cỡ nào; Cluster Autoscaler đảm bảo có đủ Node để chứa chúng. Ba tầng phối hợp: HPA phản ứng nhanh (giây–phút) với biến động traffic, CA phản ứng chậm hơn (phút) để cấp hạ tầng, VPA chỉnh dài hạn để tối ưu kích thước.
Tình huống thực tế
Ví dụ 1: Sàn TMĐT gặp flash sale — HPA + Cluster Autoscaler phối hợp
Một sàn thương mại điện tử tầm trung ở TP.HCM (gọi là ShopViet) chạy API giỏ hàng trên EKS. Ngày thường họ giữ 6 Pod, mỗi Pod request 500m CPU. Vào 20h mỗi tối có flash sale, request tăng vọt.
Trước khi có autoscaling, họ cố định 30 Pod cả ngày "cho an toàn" — tốn tiền cả 24 tiếng chỉ để phục vụ 30 phút cao điểm. Sau khi triển khai HPA với target CPU 60%, min 6 / max 40, hệ thống tự động: lúc 19h55 traffic bắt đầu lên, HPA scale dần từ 6 lên 34 Pod. Nhưng cluster chỉ đủ Node cho ~20 Pod, nên 14 Pod bị Pending. Cluster Autoscaler nhận ra, thêm 3 Node m5.xlarge trong khoảng 90 giây, các Pod pending được xếp chỗ và chạy.
Bài học: HPA một mình là chưa đủ nếu cluster không có sẵn "đất trống". Bạn phải bật Cluster Autoscaler song song. Và họ học thêm một bài quan trọng: 90 giây chờ Node mới là quá lâu cho một đợt spike đột ngột — nên họ cấu hình HPA scale sớm hơn một chút (giảm target xuống 55%) và giữ một lượng "overprovision" nhỏ (vài Pod placeholder priority thấp) để hấp thụ cú sốc trong khi Node mới đang khởi động.
Ví dụ 2: Startup fintech tối ưu chi phí bằng VPA ở chế độ recommendation
Một startup fintech ở Singapore phục vụ thị trường Đông Nam Á có khoảng 40 microservice. Đội DevOps phát hiện hoá đơn GKE tăng mạnh nhưng CPU cluster trung bình chỉ dùng 18%. Nguyên nhân: mỗi team tự đặt requests.cpu và requests.memory theo cảm tính, thường gấp 3–4 lần nhu cầu thật "cho chắc".
Họ bật VPA ở chế độ Off (recommendation only) cho toàn bộ service trong 2 tuần để thu thập khuyến nghị. Kết quả: VPA chỉ ra rằng một service đang request 2Gi RAM nhưng thực tế chỉ dùng đỉnh 600Mi. Sau khi điều chỉnh request theo khuyến nghị (thủ công, qua Pull Request để review), tổng request tài nguyên của cluster giảm ~45%, và nhờ đó Cluster Autoscaler tự rút bớt Node — hoá đơn giảm khoảng 30%.
Bài học: VPA không nhất thiết phải tự động sửa mọi thứ. Dùng nó như một "cố vấn đo lường" đã đủ tạo giá trị lớn. Và request được đặt đúng còn giúp HPA lẫn CA ra quyết định chính xác hơn — vì mọi tầng đều tính toán dựa trên request.
Ví dụ 3: Sự cố "autoscaling đánh nhau" tại một công ty logistics
Một công ty logistics triển khai cả HPA (theo CPU) lẫn VPA (chế độ Auto, cũng đụng tới CPU) trên cùng một service xử lý đơn hàng, vì "muốn tối ưu tối đa". Kết quả là hệ thống dao động liên tục: HPA thấy CPU cao nên thêm Pod; VPA thấy CPU cao nên tăng request CPU rồi recreate Pod; Pod bị giết và tạo lại làm metric nhảy loạn, HPA lại phản ứng sai. Trong giờ cao điểm, một số Pod bị restart liên tục, độ trễ đơn hàng tăng vọt.
Họ khắc phục bằng cách tách bạch: HPA quản CPU (scale số Pod), VPA chỉ quản memory và chỉ ở chế độ recommendation. Hệ thống ổn định trở lại.
Bài học: Đừng để hai bộ điều khiển cùng phản ứng trên cùng một tín hiệu. Autoscaling là các control loop, và giống mọi hệ thống điều khiển, hai vòng lặp chống nhau sẽ tạo dao động thay vì cân bằng.
Hướng dẫn từng bước
Dưới đây là quy trình triển khai HPA cơ bản — tầng bạn sẽ dùng nhiều nhất.
Bước 1 — Cài Metrics Server. HPA cần nguồn metric. Trên hầu hết cluster managed (EKS/GKE/AKS) Metrics Server đã có sẵn hoặc cài một dòng:
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl top pods # kiểm tra: nếu ra số liệu là OK
Bước 2 — Khai báo resource requests trong Deployment. Không có bước này thì HPA theo CPU vô dụng:
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Bước 3 — Tạo HPA. Cách nhanh bằng lệnh:
kubectl autoscale deployment cart-api --cpu-percent=60 --min=3 --max=20
Hoặc khai báo bằng YAML (khuyến nghị vì quản lý được bằng Git/IaC):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: cart-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: cart-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleDown:
stabilizationWindowSeconds: 300
Lưu ý behavior.scaleDown.stabilizationWindowSeconds: 300 — bắt HPA chờ 5 phút trước khi rút Pod, tránh việc giảm Pod quá vội rồi lại phải thêm ngay.
Bước 4 — Bật Cluster Autoscaler ở tầng hạ tầng. Trên EKS/GKE, bạn cấu hình node group có minSize/maxSize và bật autoscaler (hoặc dùng Karpenter). Đây là việc thiết lập cluster, thường làm qua Terraform.
Bước 5 — Kiểm chứng. Tạo tải giả để xem HPA phản ứng:
kubectl run -it load --rm --image=busybox -- /bin/sh -c "while true; do wget -q -O- http://cart-api; done"
kubectl get hpa cart-api --watch
Quan sát cột TARGETS (CPU hiện tại/mục tiêu) và REPLICAS tăng dần.
Lỗi thường gặp & mẹo
- Quên khai báo resource requests → HPA hiển thị
TARGETS: <unknown>/60%và không scale. Đây là lỗi phổ biến nhất. Luôn đặt requests. - Không cài / lỗi Metrics Server → HPA không có dữ liệu. Kiểm tra bằng
kubectl top pods. - HPA scale nhưng Pod kẹt Pending → cluster hết Node và chưa bật Cluster Autoscaler. HPA và CA phải đi cùng nhau.
- Đặt
maxReplicasquá cao mà không đặt limit chi phí → một bug gây spike CPU giả có thể khiến hệ thống scale lên hàng trăm Pod, hoá đơn cloud "nổ". Đặt max hợp lý và có cảnh báo (alert). - Dùng HPA + VPA Auto trên cùng metric → dao động, restart liên tục (như ví dụ 3). Tách metric hoặc để VPA ở chế độ recommendation.
- Scale down quá nhanh gây "flapping" → dùng
stabilizationWindowSecondsđể làm mượt. - PodDisruptionBudget (PDB): khi Cluster Autoscaler muốn rút Node, nó phải evict Pod. Đặt PDB để đảm bảo tối thiểu số Pod luôn sẵn sàng, tránh gián đoạn dịch vụ khi scale down.
- Mẹo scale theo tín hiệu đúng: CPU không phải lúc nào cũng là chỉ số tốt. Một API bị nghẽn bởi I/O hoặc chờ database có thể CPU thấp nhưng độ trễ cao. Với những trường hợp này, dùng custom metric (request per second, độ dài hàng đợi) qua Prometheus Adapter hoặc KEDA. KEDA đặc biệt mạnh khi bạn cần scale theo event (số message Kafka/SQS) và thậm chí scale về 0 khi không có việc.
- Cold start: nhớ rằng Node mới cần thời gian khởi động (kéo image, healthcheck). Giữ overprovision nhỏ hoặc dùng image nhẹ để giảm độ trễ phản ứng.
Bài tập thực hành
- Dựng HPA cơ bản: Trên một cluster thử nghiệm (minikube hoặc kind), deploy một web app đơn giản có khai báo requests, tạo HPA target CPU 50%, min 2 max 10. Dùng lệnh tạo tải và quan sát
kubectl get hpa --watchcho tới khi replica tăng. Ghi lại mất bao lâu để scale lên và bao lâu để scale xuống.
- Trải nghiệm VPA recommendation: Cài VPA, tạo một VPA object ở chế độ
Offcho một Deployment. Chạy workload vài phút rồi xemkubectl describe vpa <ten>để đọc phần khuyến nghị (Target/Lower/Upper bound). So sánh với request bạn đang đặt — bạn đang đặt dư hay thiếu?
- Mô phỏng Pending: Giới hạn cluster còn ít tài nguyên, đặt
maxReplicascao và tạo tải mạnh để một số Pod rơi vàoPending. Chạykubectl describe pod <pod-pending>và đọc phần Events — bạn sẽ thấy thông báo thiếu CPU/memory. Đây chính là tín hiệu Cluster Autoscaler dùng để quyết định thêm Node.
- Tư duy thiết kế: Với một service database single-leader (không scale ngang được), bạn sẽ chọn tầng autoscaling nào và chế độ gì? Viết 3–4 câu giải thích lựa chọn của bạn.
Tóm tắt
Kubernetes có ba tầng autoscaling, mỗi tầng giải quyết một bài toán khác nhau:
- HPA (Horizontal Pod Autoscaler): thêm/bớt số lượng Pod theo metric (CPU, RAM, hoặc custom). Phản ứng nhanh, dùng nhiều nhất, hợp với service stateless. Đây là lựa chọn mặc định của bạn.
- VPA (Vertical Pod Autoscaler): điều chỉnh kích thước request/limit của từng Pod. Tuyệt vời ở chế độ recommendation để chống lãng phí và đặt request đúng; ở chế độ Auto thì cẩn thận vì phải recreate Pod và không được đụng cùng metric với HPA.
- Cluster Autoscaler (hoặc Karpenter): thêm/bớt số lượng Node để đảm bảo luôn có chỗ cho Pod. Bắt buộc đi kèm HPA nếu bạn muốn scale thật.