HPA to not scale correctly

HPA 無法正確 Auto Scaling

這篇文章將介紹我們在客戶端的 GKE 上使用 HPA 時遭遇到的 Bug。

環境描述

Kubernetes version: 1.27.8-gke.1067004

事件發生

客戶的 GKE 上遭遇一個十分詭異的問題,部署 HPA 後,無論 resource usage 是否到達 threshold,會馬上 scale up 到 max replica count,並且永遠不會 scale down,從 HPA 的 event 上看來,HPA controller 確實認為 resource usage 超過 threshold:

New size: 3; reason: memory resource utilization (percentage of request) above target

以下是 HPA 設定:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server
spec:
  scaleTargetRef:
    kind: Deployment
    name: api-server
    apiVersion: apps/v1
  minReplicas: 1
  maxReplicas: 3
  metrics: 
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

在 GKE 上的 workload 查看 HPA 的狀態,當前的 memory usage 是 33%,threshold 則是 80%:

gke-hpa-0

很明顯的,current value 明明沒有到達 target value,但是 HPA 仍然將 replica count 升到 3:

gke-hpa-1

調查經過

一開始認為是 metrics server 的問題,但又覺得十分不合理,假設 metrics server 回傳值是錯誤的,那 HPA 畫面上顯示的值是怎麼來的。透過以下API,可以獲得當前 metrics value:

kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/<namespace>/pods/<pod-name>"

再來調查相關 issue 及 kubernetes 在 1.27 版本的 change log,但很遺憾的,所有情境都與現在 不相符:

於是我棄用了 type: Resource,改用 external metrics 功能,透過 HPA 存取 Prometheus 提供 metrics API 進行 autoscaling ,但是問題 仍然發生:

hpa-keda

我還發現,如果調高 threshold 到一個很大的值,例如 memory 我調整為 400%,則 HPA 會下降 replica count 為 2,我推測 HPA 顯示的值與實際計算的內容不相符。

問題解決

後來我在相同 Kubernetes 版本的 GKE 上部署一個全新的服務進行測試,所有 Demo codes 都來自 Kubernetes HorizontalPodAutoscaler Walkthrough,結果十分正常,證實這個 k8s 版本的 HPA 是可運作的,於是我開始調查 Demo codes 與 客戶端服務的差異。

最後發現,客戶服務中的 Deployment 中的 selector.matchlabels 有重複的情況,而重複的 selector.matchlabels 可能會導致 HPA 產生 bug:

deployment

將其改為不同的 selector.matchlabels 後,HPA 的行為就完全符合預期了:

  1. 壓測前 (CPU: 1% / 50%, Memory: 26% / 80%, replica: 1)

scale-0

  1. 壓測後 (CPU: 102% / 50%, Memory: 41% / 80%, replica: 3 (still scaling…))

scale-1

結論

後續有找到相關的 issue: Overlapping Deployment matchLabels causes HPA to not scale correctly, 我相信我遇到的 bug 正如底下的留言有關,是由於 HPA 的行為所導致。

work

我沒有官方文件中看到相關的文章,也沒有證實 HPA 工作行為是否跟這則留言相符,不過確實在改變 selector.matchlabels 後,問題再也沒有發生。