Resource Requests/Limits và Autoscaling (HPA)

K
Kai··5 min read

Hai chuyện gắn bó: muốn Kubernetes autoscale theo tải, trước hết mỗi pod phải khai báo nó cần bao nhiêu tài nguyên. Bài này đi từ requests/limits (nền tảng để scheduler và autoscaler làm việc) tới HorizontalPodAutoscaler — và ta sẽ tạo tải thật để tận mắt thấy cluster tự thêm pod.

requests và limits: hai con số, hai vai trò

Trong spec container, bạn khai báo tài nguyên qua hai khái niệm thường bị nhầm:

resources:
  requests:           # mức ĐẢM BẢO — scheduler dựa vào đây để chọn node
    cpu: 200m         # 200 milli-CPU = 0.2 lõi
    memory: 64Mi
  limits:             # mức TRẦN — vượt sẽ bị chặn/giết
    cpu: 500m
    memory: 128Mi
  • requests là mức tài nguyên đảm bảo dành cho pod. Scheduler (Bài 1) dùng con số này để quyết định node nào còn đủ chỗ — pod chỉ được đặt lên node có đủ requests còn trống. Đây là điều giúp Kubernetes xếp pod hợp lý mà không nhồi quá tải một node.
  • limitstrần. Vượt limit CPU → container bị throttle (chậm lại, không bị giết). Vượt limit memory → container bị OOMKilled (giết vì hết bộ nhớ). Limit bảo vệ cluster khỏi một pod lỗi ngốn sạch tài nguyên hàng xóm.

Đơn vị: CPU tính theo lõi, 1 = một lõi, 500m = nửa lõi (m = milli). Memory theo byte với hậu tố Mi/Gi (mebibyte/gibibyte).

Việc đặt requests đúng quan trọng hơn người mới nghĩ: đặt quá thấp thì node bị nhồi quá tải (pod tranh nhau, chậm); đặt quá cao thì lãng phí (node trống mà scheduler tưởng đầy). Và như sẽ thấy, HPA cần requests để tính phần trăm sử dụng.

QoS: thứ tự bị "hi sinh" khi node cạn tài nguyên

Cách bạn đặt requests/limits quyết định QoS class của pod — và khi node hết bộ nhớ, Kubernetes giết pod theo lớp này:

  • Guaranteed (requests = limits): được bảo vệ nhất, bị giết sau cùng.
  • Burstable (có requests < limits): ở giữa.
  • BestEffort (không khai báo gì): bị giết đầu tiên khi node thiếu tài nguyên.

Bài học: pod quan trọng nên đặt requests/limits rõ ràng để không bị xem là "hàng bỏ đi" lúc khủng hoảng.

HorizontalPodAutoscaler: tự tăng/giảm số pod

Scale tay bằng kubectl scale (Bài 4) là phản ứng thủ công. HPA tự động hoá: nó theo dõi một chỉ số (thường là CPU) và tự đổi số replicas để giữ chỉ số quanh mức mục tiêu. Tải cao → thêm pod; tải hạ → bớt pod.

HPA cần biết tải hiện tại, mà nguồn số liệu là metrics-server. Cluster trắng không có sẵn — trên minikube bật bằng addon:

minikube addons enable metrics-server

Có metrics-server rồi, kubectl top mới hoạt động:

kubectl top pods -l run=php-apache
NAME                          CPU(cores)   MEMORY(bytes)
php-apache-69b4854d9f-t44x4   11m          21Mi

Dựng HPA và tạo tải thật

Triển khai một app demo (image hpa-example — một trang PHP cố tình tốn CPU mỗi request) với requests.cpu: 200m, rồi gắn HPA:

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=5
kubectl get hpa php-apache
NAME         REFERENCE               TARGETS       MINPODS   MAXPODS   REPLICAS
php-apache   Deployment/php-apache   cpu: 0%/50%   1         5         1

HPA sẽ giữ CPU trung bình quanh 50% của requests, trong khoảng 1–5 bản sao. Đang rảnh nên CPU 0%, giữ 1 pod. Giờ đổ tải — một pod cứ gọi service liên tục:

kubectl run load-generator --image=busybox:1.36 --restart=Never -- \
  /bin/sh -c "while true; do wget -q -O- http://php-apache; done"

Theo dõi HPA mỗi 15 giây:

[15s]  cpu: 0%/50%     REPLICAS 1
[45s]  cpu: 94%/50%    REPLICAS 1     ← tải tăng, vượt mục tiêu
[60s]  cpu: 94%/50%    REPLICAS 2     ← HPA thêm pod
[105s] cpu: 154%/50%   REPLICAS 2 → 4 ← vẫn cao, thêm nữa
kubectl get pods -l run=php-apache
NAME                          READY   STATUS    AGE
php-apache-69b4854d9f-96vzq   1/1     Running   9s     ← pod mới
php-apache-69b4854d9f-j58rj   1/1     Running   69s    ← pod mới
php-apache-69b4854d9f-t44x4   1/1     Running   4m32s  ← pod gốc
php-apache-69b4854d9f-tfxwh   1/1     Running   9s     ← pod mới

Tận mắt: CPU vọt lên 94% rồi 154% (vượt xa mục tiêu 50%), HPA phản ứng bằng cách tăng dần từ 1 → 2 → 4 bản sao để chia tải. Không ai gõ lệnh — control loop của HPA tự làm. Đây là requests phát huy tác dụng: "154%" nghĩa là dùng gấp 1.5 lần requests.cpu (200m), nên HPA biết cần bao nhiêu pod để kéo trung bình về 50%.

Scale xuống và một lưu ý

Khi dừng tải, HPA cũng giảm pod — nhưng thận trọng và chậm hơn: mặc định nó chờ một khoảng ổn định (cỡ 5 phút) trước khi scale down, tránh "giật cục" khi tải dao động. Tăng nhanh để kịp phục vụ, giảm chậm để ổn định — một thiết kế hợp lý.

Ngoài HPA (scale số pod), Kubernetes còn VPA (đổi requests/limits của pod) và Cluster Autoscaler (thêm/bớt node). Ba tầng autoscale này thường phối hợp ở production. Series nền tảng này dừng ở HPA — phổ biến và dễ hiểu nhất.

Tổng kết

Mỗi container nên khai báo requests (mức đảm bảo — scheduler dùng để xếp pod, HPA dùng để tính %) và limits (trần — vượt CPU bị throttle, vượt memory bị OOMKilled). Cách đặt hai con số này quyết định QoS class (Guaranteed > Burstable > BestEffort) — tức thứ tự bị hi sinh khi node cạn tài nguyên. HorizontalPodAutoscaler tự đổi số bản sao để giữ chỉ số (thường CPU) quanh mục tiêu — cần metrics-server. Demo cho thấy HPA tăng 1→4 pod khi CPU vọt lên 154%, và scale xuống chậm có chủ đích.

Tới giờ ta toàn dùng Deployment cho app không trạng thái. Bài 12 gặp các loại workload khác — StatefulSet (app có trạng thái), DaemonSet (mỗi node một pod), Job/CronJob (chạy rồi xong) — và khi nào dùng cái nào.