iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
Kubernetes

從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台系列 第 25

[Day 25] 彈性伸縮:根據負載自動擴展 (HPA) 的實戰配置 —— 讓叢集在高峰期自動增加副本,離峰期自動縮減省錢。

  • 分享至 

  • xImage
  •  

Day 25: 彈性伸縮:根據負載自動擴展 (HPA) 的實戰配置

讓叢集在高峰期自動增加副本,離峰期自動縮減省錢。

1. 靜態配置的問題

Deployment 裡把 replicas 寫死是最簡單的做法,但也是最沒有彈性的做法:寫死成 2,流量尖峰時可能撐不住;寫死成 10,離峰時段大部分資源在閒置。Horizontal Pod Autoscaler (HPA) 讓副本數跟著實際負載動態調整。

2. 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 就沒有基準值可以算百分比。

3. 前置需求:metrics-server

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 提過,雲端部署暫時擱置),先記錄本機這邊確實需要它。

4. 實測:施壓與擴容

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);
}

完整的擴容過程:

https://ithelp.ithome.com.tw/upload/images/20260827/201825491ASmMvsftc.png

▲ 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%。

5. 一個真實的意外:OOMKilled

準備這次實測時,第一次用了 30 個併發連線,結果 wafer-backend 的 Pod 被 OOMKilled(Exit Code: 137)而不是正常擴容。原因是:

  • 每個併發請求都會在記憶體裡建立獨立的 pandas DataFrame 做運算
  • Deployment 原本沒有設定任何 resources.limits.memory,後來為了讓 HPA 可以運作補上了 request/limit,但 limit 設得偏保守(512Mi)
  • 30 個並發請求同時進行 groupby/scipy 運算,記憶體峰值直接超過 512Mi

limits.memory 調到 1Gi、把併發數降到 12 之後才穩定跑完整個擴容流程。這其實暴露了一個比 HPA 本身更值得注意的問題:CPU 型 HPA 只解決 CPU 瓶頸,如果應用本身是記憶體密集型,CPU 還沒衝高、記憶體就先被打爆,Pod 會直接重啟而不是水平擴展。針對這類工作負載,比較合適的做法是同時監控 CPU 與記憶體(HPA 支援多指標)、或改用 VPA (Vertical Pod Autoscaler) 調整單一 Pod 的資源配置。這部分在 Day 28 效能調優會再深入。

6. 縮容行為

負載降下來之後,HPA 不會立刻把多出來的 Pod 砍掉——預設有一段 stabilization window(通常 5 分鐘),避免流量短暫下降就縮容、緊接著又要重新擴容的「抖動」。這個行為可以透過 behavior.scaleDown.stabilizationWindowSeconds 調整。

7. 小結

HPA 讓副本數跟著真實負載走,但它不是萬能藥——資源 request/limit 沒設對,或應用本身的瓶頸不在 CPU,HPA 一樣救不了場。明天進入資料庫演進的主題:如何用 Liquibase 管理 Schema 變更,而不是手動連進資料庫下 SQL。


上一篇
[Day 24] 分布式追蹤 (Distributed Tracing):使用 OpenTelemetry 洞察微服務間的流轉 —— 深入學習 OTel 與 Jaeger 的完整請求鏈路。
下一篇
[Day 26] 資料庫演進:在 K8S 上使用 Liquibase 管理 DB 遷移 —— 自動化更新資料庫 Schema,告別手動執行 SQL 的風險。
系列文
從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言