HPA原理
K8S彈性伸縮,指在大業務量情況下,當前容器資源如cpu,內存,自定義指標等,已超出正常設定的範圍時進行的自動擴容操作,將業務負載到擴容後的容器上,降低容器壓力,直到達到HPA設定的容器數量上限,當業務量降低後,實現自動縮容操作。Kubernetes 中的 Metrics Server 持續採集所有 Pod 副本的指標數據。HPA 控制器通過 Metrics Server 的 API(Heapster 的 API 或聚合 API)獲取這些數據,基於用戶定義的擴縮容規則進行計算,得到目標 Pod 副本數量。當目標 Pod 副本數量與當前副本數量不同時,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)發起 scale 操作,調整 Pod 的副本數量,完成擴縮容操作。
HPA的具有擴縮容冷卻週期,防止因網絡抖動而造成的不必要擴縮容操作
擴容冷卻時間默認值:3分鐘
縮容冷卻時間默認值:5分鐘
可以通過調整kube-controller-manager組件啓動參數設置冷卻時間:
--horizontal-pod-autoscaler-downscale-delay :擴容冷卻
--horizontal-pod-autoscaler-upscale-delay :縮容冷卻
HPA發展初期只支持內存,cpu的自動擴縮容操作,不支持自定義指標,發展至今,已經可以通過第三方插件與Prometheus等監控服務進行交互,獲取到自定義指標,並轉換成apiserver能夠理解的內容,供HPA進行自動化擴縮容操作。如下圖
HPA發展歷程
目前 HPA 已經支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三個大版本 。
目前大多數人比較熟悉是autoscaling/v1,這個版本只支持CPU一個指標的彈性伸縮。
而autoscaling/v2beta1增加了支持自定義指標,autoscaling/v2beta2又額外增加了外部指標支持。
而產生這些變化不得不提的是Kubernetes社區對監控與監控指標的認識與轉變。從早期Heapster到Metrics Server再到將指標邊界進行劃分,一直在豐富監控生態。
傳統HPA,只針對cpu,內存進行擴縮容編寫方式也很簡單,可以通過yaml,也可以通過kubectl 命令行形式設定閥值。
v1版本:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 50
v2beta2版本:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: 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/v1beta1
kind: Ingress
name: main-route
target:
type: Value
value: 10k
- type: External
external:
metric:
name: queue_messages_ready
selector: "queue=worker_tasks"
target:
type: AverageValue
averageValue: 30
Resource:指的是當前伸縮對象下的pod的cpu和memory指標,只支持Utilization和AverageValue類型的目標值。
Object:指的是指定k8s內部對象的指標,數據需要第三方adapter提供,只支持Value和AverageValue類型的目標值。
Pods:指的是伸縮對象Pods的指標,數據需要第三方的adapter提供,只允許AverageValue類型的目標值。
External:指的是k8s外部的指標,數據同樣需要第三方的adapter提供,只支持Value和AverageValue類型的目標值。
基於Prometheus自定義指標縮放
1.部署Prometheus
參考我之前的博客部署即可
2.部署Prometheus Adapter
但是prometheus採集到的metrics並不能直接給k8s用,因爲兩者數據格式不兼容,還需要另外一個組件(k8s-prometheus-adpater),將prometheus的metrics 數據格式轉換成k8s API接口能識別的格式,轉換以後,因爲是自定義 API,所以還需要用Kubernetes aggregator在主APIServer中註冊,以便直接通過/apis/來訪問。
直接使用Helm Charts安裝
# wget https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
# tar zxvf helm-v3.0.0-linux-amd64.tar.gz
# mv linux-amd64/helm /usr/bin/
# helm repo add stable http://mirror.azure.cn/kubernetes/charts
# helm repo update
# helm repo list
# helm install prometheus-adapter stable/prometheus-adapter --namespace kube-system --set prometheus.url=http://prometheus.kube-system,prometheus.port=9090
# helm list -n kube-system
確保適配器adapter註冊到apiserver
# kubectl get apiservices |grep custom
# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"
3.創建metrics deployment
容器需要暴露出讓prometheus獲取數據的端口,metrics路徑,需要和開發商量好,服務暴露在外的需要監控的指標放在/metrics路徑下
注意:鏡像爲私人鏡像,需要實驗的話,需要進行替換
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: metrics-app
name: metrics-app
spec:
replicas: 3
selector:
matchLabels:
app: metrics-app
template:
metadata:
labels:
app: metrics-app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "80"
prometheus.io/path: "/metrics"
spec:
containers:
- image: 172.30.0.109/metrics-app
name: metrics-app
ports:
- name: web
containerPort: 80
resources:
requests:
cpu: 200m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: metrics-app
labels:
app: metrics-app
spec:
ports:
- name: web
port: 80
targetPort: 80
selector:
app: metrics-app
訪問容器/metrics路徑,得到總共http訪問量,經過prometheus指標轉換爲QPS
4.創建HPA規則
針對容器QPS進行擴縮容操作,Pods類型只支持averageValue,deployment最大擴容數設爲10。
HPA yaml:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: metrics-app-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: metrics-app
minReplicas: 1
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 800m # 800m 即0.8個/秒
配置好HPA後,hpa還不能獲取到http_requests_per_second的數據,kubetcl get hpa看到的獲取指標是unknown,需要在prometheus adapter適配器中配置http_requests_per_second
相當於白名單,去獲取prometheus中的指標數據。
修改prometheus adapter configmap
# kubectl edit cm -n kube-system prometheus-adapter
新增:
- seriesQuery: 'http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}'
resources:
overrides:
kubernetes_namespace: {resource: "namespace"}
kubernetes_pod_name: {resource: "pod"}
name:
matches: "^(.*)_total"
as: "${1}_per_second"
metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
這裏主要是利用promSQL的形式通過將http_requests_total轉換成一個區間的平均訪問量,如上兩分鐘,求容器所有的和,即爲QPS
注意:將/metrics中的http_requests_total名稱替換爲http_requests_per_second,HPA根據http_requests_per_second去獲取指標數據進行擴縮容操作
prometheus-adapter配置修改後,需要重啓容器加載新的配置
到這一步,指標已經獲取到了
# kubectl get hpa
5.測試HPA
進行壓測
# yum install -y httpd-tools
使用ab命令對metrics-app service進行壓力測試
查看HPA,指標數據已經打滿,deployment下的容器已經擴容到了10個,等壓力測試結束,就會自動縮容