讓叢集在高峰期自動增加副本,離峰期自動縮減省錢。
Deployment 裡把 replicas 寫死是最簡單的做法,但也是最沒有彈性的做法:寫死成 2,流量尖峰時可能撐不住;寫死成 10,離峰時段大部分資源在閒置。Horizontal Pod Autoscaler (HPA) 讓副本數跟著實際負載動態調整。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: wafer-backend-hpa
namespace: k8sdemo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: wafer-backend
minReplicas: 1
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
averageUtilization: 50 是相對於 CPU request(不是 limit)計算的百分比。這代表 HPA 需要每個 Pod 都設定 resources.requests.cpu,沒有設定的話 HPA 完全無法運作——沒有 request 就沒有基準值可以算百分比。
HPA 依賴 metrics-server 提供的 CPU/記憶體用量數據,K8S 本身不內建這個元件(Docker Desktop 的本機叢集也一樣)。用 Helm 裝:
helm install metrics-server metrics-server/metrics-server \
--namespace kube-system \
--set args={--kubelet-insecure-tls}
--kubelet-insecure-tls 是因為本機環境的 kubelet 憑證是自簽的,metrics-server 預設會驗證憑證鏈而失敗;託管式 K8S(例如 OKE)通常憑證鏈是完整的,不需要這個參數——但這點目前還沒有實際的雲端環境可以驗證(Day 9 提過,雲端部署暫時擱置),先記錄本機這邊確實需要它。
wafer-backend 的 /stats、/regression、/cdf 端點會做實際的 pandas/scipy 運算,比起單純回傳 JSON 的端點更適合拿來製造 CPU 負擔。用 k6 打 12 個併發連線持續施壓:
export const options = {
scenarios: { cpu_burn: { executor: 'constant-vus', vus: 12, duration: '3m' } },
};
export default function () {
const paths = ['/stats/Lot1?parameter=Thickness', '/regression/Lot1?parameter=Thickness', '/cdf/Lot1?parameter=Thickness'];
http.get(`http://localhost:8000${paths[Math.floor(Math.random() * paths.length)]}`);
sleep(0.05);
}
完整的擴容過程:

▲ HPA 實測:CPU 衝到 request 的 500% 後,Replicas 從 1 自動增加到 5
施壓前 wafer-backend-hpa 顯示 cpu: 4%/50%,Replicas 為 1。施壓後單一 Pod 的 CPU 用量衝到 request 值(100m)的 500%(即 500m,已達 limits.cpu 上限),HPA 判定超標,依照 scaleUp policy(15 秒內最多新增 4 個 Pod)把 Replicas 一次拉到 5。新 Pod 分攤流量後,原本吃緊的 CPU 立刻回落到 3%。
準備這次實測時,第一次用了 30 個併發連線,結果 wafer-backend 的 Pod 被 OOMKilled(Exit Code: 137)而不是正常擴容。原因是:
resources.limits.memory,後來為了讓 HPA 可以運作補上了 request/limit,但 limit 設得偏保守(512Mi)把 limits.memory 調到 1Gi、把併發數降到 12 之後才穩定跑完整個擴容流程。這其實暴露了一個比 HPA 本身更值得注意的問題:CPU 型 HPA 只解決 CPU 瓶頸,如果應用本身是記憶體密集型,CPU 還沒衝高、記憶體就先被打爆,Pod 會直接重啟而不是水平擴展。針對這類工作負載,比較合適的做法是同時監控 CPU 與記憶體(HPA 支援多指標)、或改用 VPA (Vertical Pod Autoscaler) 調整單一 Pod 的資源配置。這部分在 Day 28 效能調優會再深入。
負載降下來之後,HPA 不會立刻把多出來的 Pod 砍掉——預設有一段 stabilization window(通常 5 分鐘),避免流量短暫下降就縮容、緊接著又要重新擴容的「抖動」。這個行為可以透過 behavior.scaleDown.stabilizationWindowSeconds 調整。
HPA 讓副本數跟著真實負載走,但它不是萬能藥——資源 request/limit 沒設對,或應用本身的瓶頸不在 CPU,HPA 一樣救不了場。明天進入資料庫演進的主題:如何用 Liquibase 管理 Schema 變更,而不是手動連進資料庫下 SQL。