前言
在之前的
文章中,我們介紹了
kubernetes-cronhpa-controller
是如何通過設定定時的方式觸發容器的水準副本伸縮,但是在實際的場景下,雖然定時伸縮對于負載有規律的應用比較友好,但是應用為了防止突發的流量沖擊,還是會配置HPA來做最後的保障的。那麼CronHPA與HPA之間該怎麼選擇呢?
定時伸縮元件相容HPA
在抉擇什麼時候需要CronHPA,什麼時候使用HPA的時候,我們在思考是否可以将CronHPA與HPA一起使用,如果一起使用會有什麼需要解決的問題呢?首先我們先看CronHPA的模闆定義
apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: cronhpa-sample
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment-basic
jobs:
- name: "scale-down"
schedule: "30 */1 * * * *"
targetSize: 1
- name: "scale-up"
schedule: "0 */1 * * * *"
targetSize: 3
在CronHPA中是通過
scaleTargetRef
字段來擷取伸縮對象的,并通過jobs的crontab規則定時伸縮執行個體的副本。
那麼我們再來看下HPA的模闆定義
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment-basic
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
HPA也是通過
scaleTargetRef
來定義伸縮的對象,并通過資源使用率來判斷伸縮的情況。如果同時設定CronHPA與HPA,那麼就會出現HPA與CronHPA同時操作一個
scaleTargetRef
的場景,而兩者之間又互相獨立無法感覺,這樣就會出現兩個controller各自工作,後執行的會覆寫先執行的結果。

這個問題的本質是兩個controller無法互相感覺,進而造成了異常,當回過頭來看這個問題的時候,其實我們可以發現HPA早期也有同樣的問題,開發者如果希望通過用兩個監控名額同時作用到HPA的時候,如果設定兩個HPA對象,會出現類似的問題,在解決這個問題的時候,是通過在HPA對象中定義metrics字段,将多個metrics合并到一個HPA對象中來實作的,例如:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment-basic
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 50
當兩個metrics觸發彈性的個數不同的時候,會根據穩定性第一的原則,優先彈出更多的副本或者在縮容時保留更多的副本。那麼是否CronHPA和HPA也可以通過這個方案進行整合,答案是
Yes and No
。因為的确可以通過
alibaba-cloud-metrics-adapter
将定時的資料通過External Metrics的方式進行轉換,然後通過HPA中使用External Metrics的方式進行整合和比對。但是這樣會帶來的結果就是,我們需要通過HPA的結構去表達CronHPA的規則,然後再通過Metrics Adapter的模型去轉換時間資訊與副本計算。從模型上來看,這個方式看似相容了HPA,但是實際上對定時伸縮的可讀性、學習成本、出錯診斷、審計與離線都帶來了新的挑戰。
那麼是否還有其他的方法可以實作CronHPA與HPA的相容呢?我們将視角放回
scaleTargetRef
,還記得HPA是怎麼伸縮Deployment的Pod嗎,是HPA将Deployment配置在了
scaleTargetRef
的字段下,然後Deployment通過自身定義查找到了ReplicaSet,在通過ReplicaSet調整了真實的副本數目。
那麼從這個角度出發,我們有了一個大膽的想法,是否可以将
scaleTargetRef
設定為HPA對象,然後通過HPA對象來尋找真實的
scaleTargetRef
。
apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: cronhpa-sample
spec:
scaleTargetRef:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
name: nginx-deployment-basic-hpa
jobs:
- name: "scale-down"
schedule: "30 */1 * * * *"
targetSize: 1
runOnce: true
- name: "scale-up"
schedule: "0 */1 * * * *"
targetSize: 3
runOnce: true
這樣設計的好處是,首先CronHPA可以感覺HPA目前的狀态,明确的知曉HPA的min、max、desired的數值,同時也知道HPA
scaleTargetRef
所對應的目前replicas。那麼本着穩定性原則,我們要如何操控HPA呢?
hpa(min/max) | cronhpa | deployment | result | 場景 |
---|---|---|---|---|
1/10 | 5 | hpa(1/10) deployment 5 | 定時和目前一緻,無需變更 | |
4 | 目前高于定時,保留目前副本 | |||
6 | hpa(6/10) deployment 6 | 定時高于目前,保留定時副本 定時高于HPA下限,修改HPA下限 | ||
5/10 | hpa(4/10) deployment 5 | 定時低于目前,保留目前副本 定時低于HPA下限,修改HPA下限 | ||
11 | hpa(11/11) deployment 11 | 定時高于HPA上限,修改HPA上限 |
如上圖是以,CronHPA會通過調整HPA的方式進行感覺,CronHPA要達到的副本和目前副本取大值,來判斷是否要擴容以及修改HPA的上限。CronHPA要達到的副本和HPA的配置取小值,判斷是否要修改HPA的下限。簡單而言,CronHPA不會直接調整Deployment的副本數目,而是通過HPA來操作Deployment,這樣就可以避免HPA和CronHPA的沖突問題了。
最後
定時伸縮CronHPA和HPA都是線上業務場景下非常重要的功能,不論使用何種的相容與适配的方式,穩定性第一的原則是不能改變的,開發者如果對CronHPA感興趣,歡迎
送出PR