我們平時部署web服務,當服務壓力大撐不住的時候,我們會加機器(加錢);一般沒有上容器編排是手動加的,臨時加的機器,臨時部署的服務還要改Nginx的設定,最後回收機器的時候,也是手動回收,手動修改Nginx的,挺麻煩的其實;
而K8s是支援這整個流程的自動化的,也就是HPA;
HPA:全稱Horizontal Pod Autoscaler ,對應中文叫Pod的自動水平伸縮;
Pod的水平伸縮是水平方向增加/減少Pod的數量;
Pod的垂直伸縮則是垂直方向上控制Pod的硬體,比如增加/縮減CPU、記憶體等資源;
k8s的HPA一般會根據一個具體的指標來做,比如常見CPU、記憶體的負載;也可以根據web服務的吞吐量、單位時間內的傳輸位元組數等;另外還可以根據自定義的指標,比如RabbitMQ的佇列數量、Webhook等;
我這裡先講講怎麼根據CPU、記憶體的負載來做HPA;
$ kubectl version
Client 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 node
NAME 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
下載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-server
kubectl top node
建立一個hpa-api.yaml的檔案內容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hpa-api
spec:
selector:
matchLabels:
app: hpa-api
replicas: 1
template:
metadata:
labels:
app: hpa-api
spec:
containers:
- name: hpa-api
image: gebiwangshushu/hei-ocelot-api:1.0 #這是我寫其他文章上傳的映象,程式碼:https://github.com/gebiWangshushu/Hei.Ocelot.ApiGateway/blob/master/Hei.Api/Controllers/WeatherForecastController.cs
ports:
- containerPort: 80
resources:
requests:
cpu: 1000m
memory: 100Mi
# limits:
# cpu: 100m
# memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: hpa-api
labels:
app: hpa-api
spec:
ports:
- port: 80
nodePort: 30999
type: NodePort
selector:
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支援版本:
$ 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/v1
kind: 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: Utilization
averageUtilization: 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。
另外還有自定義指標等,需要1.23及以上版本才支援了;
建立HPA資源
kubectl apply -f HPA.yaml
檢視HPA
$ kubectl get hpa
NAMESPACE 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-api
Name: 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 4
ScalingActive 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/
https://blog.51cto.com/smbands/4903843
https://www.cnblogs.com/fanggege/p/12299923.html