基於Kubernetes的hpa實現pod例項數量的自動伸縮

DrunkCat90發表於2021-12-13

Pod 是在 Kubernetes 體系中,承載使用者業務負載的一種資源。Pod 們執行的好壞,是使用者們最為關心的事情。在業務流量高峰時,手動快速擴充套件 Pod 的例項數量,算是玩轉 Kubernetes 的基本操作。實際上這個操作還可以更加自動化,運維人員可以事先設定好規則,讓 Pod 例項的數量,在指定情況下自動的調整例項的數量,這一操作依靠 Horizontal Pod Autoscaler 來實現。

場景描述

如果企業應用的終端使用者是人,那麼它的訪問壓力情況,都會有潮汐特徵。好比一款供企業內部人員使用的OA系統,工作日的流量遠比休息日高,工作時間的流量遠比下班時間高。那麼可否讓這款 OA 系統根據流量的大小,自動調整例項的數量。令其忙時啟動足夠數量的例項抵禦訪問壓力,閒時自動降低例項數量,將資源留給其他企業應用。

下圖是某個業務系統,在 24 小時內的效能監控曲線。其吞吐率和線上人數曲線都可以反映出一定的潮汐特性:

  • 午夜 0 點直到次日早上8 點,這個系統都處於無人使用的狀態。在這一段時間裡,可以自動將業務系統的例項數量降下來,釋放一些計算資源。
  • 上午 9 點直到晚間 21 點為系統使用高峰期,最高線上人數達到 1600 人。在這一段時間裡,業務系統的例項數量可以自動提升起來,滿足業務的需要。

image-20200213120547158

關於 hpa

Kubernetes 在 1.2 版本開始支援了 Horizontal Pod Autoscaler(hpa) ,來應對 Pod 例項的自動伸縮場景。它可以基於例項的 CPU 使用率來決定是否為 Pod 進行例項數量的擴容。我們知道 Pod 的副本數量是被其控制器的配置所決定的,比如 Deployment、StatefulSet、ReplicaSet 。所以,hpa 是在獲取了 Pod 實際 CPU 使用率這一指標,和擴充套件例項的目標指標對比後,操作了其控制器來實現副本數量的擴縮的。

瞭解了以上內容後,我們起碼可以知道,在使用 hpa 進行自動伸縮的設定之前,Kubernetes 叢集和 Pod 的控制器都應該符合一定的先決條件。

  • 存在 Metrics-server。Metrics-server 是 Kubernetes 叢集範圍資源用量資料的聚合器。Pod 的 CPU 使用率這一指標,是從 Metrics-server 中獲取 CPU 實際用量之後,與控制器中指定的 Pod 資源做比後所得。大多數 Kubernetes 發行版中都已經預設安裝了 Metrics-server ,它一般部署在 kube-system 名稱空間中。
  • Pod 資源限額。既然使用的指標是 CPU 使用率,那麼就必須存在一個 CPU 可用的上限作為分母。這個上限,實際上就是在控制器中規定的 Pod 資源限額 spec.resources.limits.cpu

建立 hpa

建立 hpa 之前, 我們需要確保 Pod 控制器中規定了CPU資源限額。我當前使用的案例,使用了 Deployment 控制器。其 Pod 的 CPU 資源限額給到 500m。

Kubernetes 體系中,CPU 是一種可以再分的資源,1000m = 1 Core

kubectl get deployment demo-java -n my-namespace -o yaml

返回的結果中,包含了事先設定的資源限額資訊:

spec:
  resources:
    limits:
      cpu: 200m
      memory: 1Gi
    requests:
      cpu: 200m

最簡單的建立 hpa 的方式,是使用 kubectl autoscale 命令進行操作。下面的示例,意味著在 Pod 的 CPU 使用率超過 50% 之後,將會觸發自動伸縮,最多伸縮到 3 個例項。

kubectl autoscale deployment demo-java -n my-namespace --cpu-percent=50 --min=1 --max=3

返回結果:

horizontalpodautoscaler.autoscaling/demo-java autoscaled

建立完成後,我們可以檢視 hpa 資源的狀態:

kubectl get hpa -n my-namespace

返回結果中,自動伸縮已經被觸發,所有例項的綜合 CPU 使用率,已經低於設定的值:

hpa 資源只需要被設定一次,就會始終監控 Pod 指標,並根據設定進行自動伸縮

NAME        REFERENCE              TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
demo-java   Deployment/demo-java   49%/50%   1         3         2          3m34s

檢視 Pod 實際 CPU 使用量,可以得出相應的使用率計算值,和 hpa 中的顯示是相符的。

kubectl top pod -n my-namespace
NAME                         CPU(cores)   MEMORY(bytes)
demo-java-7d6d7d4c9c-lz8sw   197m         87Mi
demo-java-7d6d7d4c9c-52sdl   1m           90Mi

另一種建立 hpa 的方式,是通過 yaml 檔案進行定義。我們可以將已存在的 hpa 資源匯出,便可以瞭解這一資源的定義方式。

kubectl get hpa demo-java -n my-namespace -o yaml > hpa.yaml

其定義方式可以歸結如下:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: demo-java
  namespace: my-namespace
spec:
  maxReplicas: 3
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: demo-java
  targetCPUUtilizationPercentage: 50

通過命令,可以將這一yaml檔案載入進 Kubernetes 叢集:

kubectl apply -f hpa.yaml

更多的伸縮指標

在上一個章節,已經實現基於 Pod 的 CPU 使用率來進行自動伸縮。利用 CPU 使用率作為伸縮判定指標,是官方預設提供的方式。那麼是否還有其他型別的指標可以作為伸縮判定指標呢?這需要 Kubernetes 使用者自行擴充套件。

我建議從兩個方向挑選更多的伸縮判定指標。第一個方向是資源的選擇,相較於 CPU 而言,記憶體也可以作為判定指標;第二個方向是維度,相較於使用率而言,使用量也可以作為判定指標。兩個方向彼此組合之後,除了 CPU 使用率,我們還得到了另外 3 種伸縮判定指標:

  • CPU 使用量,單位 m
  • 記憶體使用率,單位 %
  • 記憶體使用量,單位 MB

在 CPU 與記憶體之間,個人更建議使用記憶體作為伸縮指標,原因是資源的不可壓縮性。CPU 是一種可以壓縮的資源,而記憶體不是,資源可壓縮意味著當 Pod 的 CPU 用量無限接近於資源限額時,對 Pod 例項的影響很小,只是效能表現不佳而已。但是當 Pod 的記憶體用量無限接近於資源限額時, Kubernetes 會對 Pod 執行 OOM kill 操作,這對業務的影響很大。如果當記憶體用量/率達到一定程度,Pod 的例項數量得到了擴充套件,就有可能避免 Pod 被系統殺死重啟。

Kubernetes 官方提供瞭如何擴充套件指標的方案,但這對於一般的使用者而言並不好掌握。我的建議是選用市面上可見的基於 Kubernetes 實現的應用管理平臺。它們往往已經將自動伸縮功能封裝成為簡單易用的功能,並且提供了上述幾種伸縮判斷指標。推薦使用北京好雨科技開源的 Rainbond 雲原生管理平臺。

Rainbond 目前已經整合了開箱可用的自動伸縮功能,下面是功能截圖。

image-20211212233055816

功能介面已經將易用性做到了極致,即使不去關注之前章節所寫的純技術內容,也可以掌握相關的設定。

在這個功能介面的示例中,將 CPU 使用率和記憶體使用率同時設定了。在 Kubernetes 中,一旦出現同個 hpa 設定中,包含了多個判定條件時,會分別計算在每一種條件下,滿足條件的 Pod 例項數量,並在所有結果之中選擇最大值作為最終的例項數量。

更多需要了解的內容,可以參考 Kubernetes 官方手冊

相關文章