寫在前面
我們平時部署web服務,當服務壓力大撐不住的時候,我們會加機器(加錢);一般沒有上容器編排是手動加的,臨時加的機器,臨時部署的服務還要改Nginx的配置,最后回收機器的時候,也是手動回收,手動修改Nginx的,挺麻煩的其實;
而K8s是支持這整個流程的自動化的,也就是HPA;
HPA介紹
HPA:全稱Horizontal Pod Autoscaler ,對應中文叫Pod的自動水平伸縮;
Pod的水平伸縮是水平方向增加/減少Pod的數量;
Pod的垂直伸縮則是垂直方向上控制Pod的硬件,比如增加/縮減CPU、內存等資源;
k8s的HPA一般會根據一個具體的指標來做,比如常見CPU、內存的負載;也可以根據web服務的吞吐量、單位時間內的傳輸字節數等;另外還可以根據自定義的指標,比如RabbitMQ的隊列數量、Webhook等;
我這里先講講怎么根據CPU、內存的負載來做HPA;
HPA實操
環境
$?kubectl?versionClient?Version:?version.Info{Major:"1",?Minor:"22",?GitVersion:"v1.22.5"Server?Version:?version.Info{Major:"1",?Minor:"22",?GitVersion:"v1.22.5"
$?kubectl?get?nodeNAME?????????????STATUS???ROLES??????????????????AGE????VERSION
docker-desktop???Ready????control-plane,master???177d???v1.22.5
檢查獲取指標是否正常
是否安裝了metrics-server
HPA是需要獲取具體的指標做伸縮的, metrics-server是提供指標的
$?kubectl??get?pod?-n?kube-system|grep???metrics-server
metrics-server-5d78c4b4f5-x5c46??????????1/1?????Running???2?(3d12h?ago)???????10d
是否正常獲取指標
$?kubectl??top?node?
docker-desktop???133m?????????0%?????2671Mi??????????16%
如果沒有的,需先安裝metrics-server
安裝metrics-server
下載yaml
wget?https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
修改yaml
spec:containers:-?args:-?--cert-dir=/tmp-?--secure-port=4443-?--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname-?--kubelet-use-node-status-port-?--metric-resolution=15s-?--kubelet-insecure-tls?#加上這個(不推薦生產這樣用)#image:?k8s.gcr.io/metrics-server/metrics-server:v0.6.1?#這個鏡像需要梯子image:?registry.cn-hangzhou.aliyuncs.com/chenby/metrics-server:v0.6.1?#換成網友阿里云的鏡像imagePullPolicy:?IfNotPresent
提交yaml
kubectl?apply?-f??components.yaml??-n?kube-system
再驗證
kubectl??get?pod?-n?kube-system|grep???metrics-serverkubectl??top?node
部署一個測試的Pod(Webapi)
創建一個hpa-api.yaml的文件內容如下:
apiVersion:?apps/v1
kind:?Deployment
metadata:name:?hpa-api
spec:selector:matchLabels:app:?hpa-apireplicas:?1template:metadata:labels:app:?hpa-apispec:containers:-?name:?hpa-apiimage:?gebiwangshushu/hei-ocelot-api:1.0?#這是我寫其他文章上傳的鏡像,代碼:https://github.com/gebiWangshushu/Hei.Ocelot.ApiGateway/blob/master/Hei.Api/Controllers/WeatherForecastController.csports:-?containerPort:?80resources:requests:cpu:?1000mmemory:?100Mi#?limits:#???cpu:?100m#???memory:?100Mi
---
apiVersion:?v1
kind:?Service
metadata:name:?hpa-apilabels:app:?hpa-api
spec:ports:-?port:?80nodePort:?30999type:?NodePortselector:app:?hpa-api
kubectl?apply?-f?hpa-api.yaml
這里創建了一個測試的webapi,所用鏡像是gebiwangshushu/hei-ocelot-api:1.0,源碼在這;這個Deployment的副本數是1,資源requests為cpu: 1000m ? ? ? ? memory: 100Mi;并且創建了一個nodePort:30999 類型的Service;
訪問看看:

172.16.6.90 是我自己k8s集群的地址;測試的webapi部署好了,我們來給他創建一個HPA(HorizontalPodAutoscaler);
創建HPA--HorizontalPodAutoscaler
查看當前HPA支持版本:
$?kubectl?api-versions|grep?autoscaling
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
autoscaling/v1: ?只支持基于CPU的自動伸縮autoscaling/v2beta1: 支持Resource Metrics(資源指標,如pod的CPU)和Custom Metrics(自定義指標)的縮放。autoscaling/v2beta2:支持Resource Metrics(資源指標,如pod的CPU)和Custom Metrics(自定義指標)和ExternalMetrics(額外指標)的縮放。
創建一個HPA.yaml的文件,內容如下:
apiVersion:?autoscaling/v2beta2?
kind:?HorizontalPodAutoscaler
metadata:name:?hpa-api
spec:scaleTargetRef:apiVersion:?apps/v1kind:?Deployment??#針對Deployment做伸縮name:?hpa-api?minReplicas:?1???#最小副本數maxReplicas:?10??#最大副本數metrics:?-?type:?Resource?resource:name:?cpu?target:type:?Utilization??#Utilization?使用率做指標averageUtilization:?50?#CPU平均使用率超requests要求的cpu的50%時,開始做擴容#type:?averageValue?#averageValue:?30??#使用平均值averageValue(平均值)?做指標
type: Utilization ? #Utilization 表示用使用率作為指標,此外還有Value 或 AverageValue
averageUtilization: ?50 ?表示CPU平均使用率超requests要求的cpu的50%時,開始做擴容
apiVersion: autoscaling/v2beta2 ?autoscaling的版本,不同版本的字段和支持的指標不一樣;
當然,這里的apiVersion: autoscaling/v2beta2 ,支持還支持很多參數,例如:
metrics:?-?type:?Resource?resource:name:?cpu?target:type:?UtilizationaverageUtilization:?60?#CPU平均負載超requests60%時,開始做擴容#?-?type:?Resource#???resource:#?????name:?cpu?#?????target:#???????type:?AverageValue?#???????averageValue:?500m?#?-?type:?Pods?#Pods類型的指標#???pods:#?????metric:#???????name:?packets-per-second#?????target:#???????type:?AverageValue#???????averageValue:?1k#?-?type:?Object#???object:#?????metric:#???????name:?requests-per-second#?????describedObject:#???????apiVersion:?networking.k8s.io/v1#???????kind:?Ingress#???????name:?main-route#?????target:#???????type:?Value#???????value:?10k#?behavior:?#控制伸縮行為速率的#???scaleDown:?#?????policies:?#支持多個策略#?????-?type:?Pods?#???????value:?4?#???????periodSeconds:?60??#60秒內#最多縮容4個pod#?????-?type:?Percent#???????value:?300??#???????periodSeconds:?60?#60秒內#最多縮容300%#?????selectPolicy:?Min#?????stabilizationWindowSeconds:?300?#???scaleUp:?#?????policies:?#?????-?type:?Pods#???????value:?5?#???????periodSeconds:?60?#60秒內#最多縮容5個pod#?????#?-?type:?Percent#?????#???value:?100??#最多擴容100%#?????#???periodSeconds:?60?#60秒內#?????selectPolicy:?Max#?????stabilizationWindowSeconds:?0
metrics
中的type字段有四種類型的值:Object、Pods、Resource、External。
Resource:指的是當前伸縮對象下的pod的cpu和memory指標,只支持Utilization和AverageValue類型的目標值。
Object:指的是指定k8s內部對象的指標,數據需要第三方adapter提供,只支持Value和AverageValue類型的目標值。
Pods:指的是伸縮對象(statefulSet、replicaController、replicaSet)底下的Pods的指標,數據需要第三方的adapter提供,并且只允許AverageValue類型的目標值。
External:指的是k8s外部的指標(比如prometheus),數據同樣需要第三方的adapter提供,只支持Value和AverageValue類型的目標值。
另外還有自定義指標等,需要1.23及以上版本才支持了;
創建HPA資源
kubectl?apply?-f?HPA.yaml
查看HPA
$?kubectl?get?hpaNAMESPACE????NAME??????REFERENCE????????????TARGETS???MINPODS???MAXPODS???REPLICAS???AGE
aspnetcore???hpa-api???Deployment/hpa-api???0%/50%????1?????????10????????1??????????8d
驗證
hpa開啟watch監控模式
$?kubectl?get?hpa?--watch
NAME??????REFERENCE????????????TARGETS???MINPODS???MAXPODS???REPLICAS???AGE
hpa-api???Deployment/hpa-api???0%/50%????1?????????10????????1??????????8d
...?
#阻塞監聽狀態
用ab壓測工具壓一下
ab?-n?200000?-c?10?http://172.16.6.90:30999/user
沒安裝的自己搜索安裝下,這里的 -n:請求個數,-c : 請求并發數
查看資源使用情況
$?kubectl?top?po
NAME??????????????????????CPU(cores)???MEMORY(bytes)
hpa-api-88ddc5c49-2vgjd???1m???????????301Mi
hpa-api-88ddc5c49-4h5pz???1m???????????300Mi
hpa-api-88ddc5c49-8c8d2???1m???????????340Mi
hpa-api-88ddc5c49-8hmnm???1m???????????300Mi
hpa-api-88ddc5c49-cgxm9???1m???????????23Mi
hpa-api-88ddc5c49-tdrc6???1m???????????23Mi
擴容情況
kubectl?get?hpa?--watch
NAME??????REFERENCE????????????TARGETS???MINPODS???MAXPODS???REPLICAS???AGE
hpa-api???Deployment/hpa-api???0%/50%????1?????????10????????1??????????8d
hpa-api???Deployment/hpa-api???262%/50%???1?????????10????????1??????????8d
hpa-api???Deployment/hpa-api???33%/50%????1?????????10????????4??????????8d
hpa-api???Deployment/hpa-api???0%/50%?????1?????????10????????6??????????8d??#這里請求結束了
伸容過程
$?kubectl?describe?hpa?hpa-apiName:??????????????????????????????????????????????????hpa-api
...
Reference:?????????????????????????????????????????????Deployment/hpa-api
Metrics:???????????????????????????????????????????????(?current?/?target?)resource?cpu?on?pods??(as?a?percentage?of?request):??262%?(2628m)?/?50%??#這里資源直接遠超1000m的50%,達到了262%?(2628m)
Deployment?pods:???????????????????????????????????????1?current?/?4?desired
..
Deployment?pods:???????????????????????????????????????1?current?/?4?desired
Conditions:Type????????????Status??Reason????????????Message----????????????------??------????????????-------AbleToScale?????True????SucceededRescale??the?HPA?controller?was?able?to?update?the?target?scale?to?4ScalingActive???True????ValidMetricFound??the?HPA?was?able?to?successfully?calculate?a?replica?count?from?cpu?resource?utilization?(percentage?of?request)ScalingLimited??True????ScaleUpLimit??????the?desired?replica?count?is?increasing?faster?than?the?maximum?scale?rateEvents:Type????Reason?????????????Age???From???????????????????????Message----????------?????????????----??----???????????????????????-------Normal??SuccessfulRescale??39s???horizontal-pod-autoscaler??New?size:?4;?reason:?cpu?resource?utilization?(percentage?of?request)?above?target?#擴容到4個Normal??SuccessfulRescale??3m11s??horizontal-pod-autoscaler??New?size:?6;?reason:?All?metrics?below?target?#擴容到6個
一旦 CPU 利用率降至 0,HPA 會自動將副本數縮減為 1;
擴容詳情
HPA 控制器基于 Master 的 kube-controller-manager 服務啟動參數 --horizontal-pod-autoscaler-sync-period 定義的探測周期(默認值為 15s) , 周期性地監測目標 Pod 的資源性能指標, 并與 HPA 資源對象中的擴縮容條件進行對比, 在滿足條件時對 Pod 副本數量進行調整。
在每個時間段內,控制器管理器都會根據每個 HorizontalPodAutoscaler 定義中指定的指標查詢資源利用率。控制器管理器找到由 scaleTargetRef
定義的目標資源,然后根據目標資源的 .spec.selector
標簽選擇 Pod, 并從資源指標 API(針對每個 Pod 的資源指標)或自定義指標獲取指標 API(適用于所有其他指標)。
對于按 Pod 統計的資源指標(如 CPU),控制器從資源指標 API 中獲取每一個 HorizontalPodAutoscaler 指定的 Pod 的度量值,如果設置了目標使用率, 控制器獲取每個 Pod 中的容器資源使用 情況, 并計算資源使用率。如果設置了 target 值,將直接使用原始數據(不再計算百分比)。接下來,控制器根據平均的資源使用率或原始值計算出擴縮的比例,進而計算出目標副本數。
需要注意的是,如果 Pod 某些容器不支持資源采集,那么控制器將不會使用該 Pod 的 CPU 使用率。
如果 Pod 使用自定義指示,控制器機制與資源指標類似,區別在于自定義指標只使用 原始值,而不是使用率。
如果 Pod 使用對象指標和外部指標(每個指標描述一個對象信息)。這個指標將直接根據目標設定值相比較,并生成一個上面提到的擴縮比例。在
autoscaling/v2beta2
版本 API 中,這個指標也可以根據 Pod 數量平分后再計算。
HorizontalPodAutoscaler 的常見用途是將其配置為從(metrics.k8s.io
、custom.metrics.k8s.io
或 external.metrics.k8s.io
)獲取指標。metrics.k8s.io
API 就是我們前面安裝Metrics Server 的插件;
擴容算法
期望副本數?=?ceil[當前副本數?*?(當前指標?/?期望指標)]
例如,如果當前指標值為
200m
,而期望值為100m
,則副本數將加倍, 因為200.0 / 100.0 == 2.0
如果當前值為50m
,則副本數將減半, 因為50.0 / 100.0 == 0.5
。如果比率足夠接近 1.0(在全局可配置的容差范圍內,默認為 0.1), 則控制平面會跳過擴縮操作。
套入上面的實例:
期望副本數?=?ceil[?1?*?(262%?/?50%)]?==?6
類似本實例的示意圖:

可以看到這里的指標,是針對所有pod的;
總結
k8s的東西太多,只學了點皮毛,有個基本的概念就趕緊記下來;k8s集群版本、HPA的版本的不同又有很多限制與字段的區別,需要后面更多的實踐與學習;
[參考]
https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details
https://blog.51cto.com/smbands/4903843
https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2beta2/
https://www.cnblogs.com/fanggege/p/12299923.html