第22章:kubernetes彈性伸縮(HPA)


2 彈性伸縮

k8s版本v1.20

2.1 傳統彈性伸縮的困境

從傳統意義上,彈性伸縮主要解決的問題是容量規划與實際負載的矛盾。

scaling-vs

藍色水位線表示集群資源容量隨着負載的增加不斷擴容,紅色曲線表示集群資源實際負載變化。

彈性伸縮就是要解決當實際負載增大,而集群資源容量沒來得及反應的問題。

1 Kubernetes中彈性伸縮存在的問題

常規的做法是給集群資源預留保障集群可用,通常20%左右。這種方式看似沒什么問題,但放到Kubernetes中,就會發現如下2個問題。

(1) 機器規格不統一造成機器利用率百分比碎片化

在一個Kubernetes集群中,通常不只包含一種規格的機器,假設集群中存在4C8G與16C32G兩種規格的機器,對於10%的資源預留,這兩種規格代表的意義是完全不同的。

scaling-machine-config

特別是在縮容的場景下,為了保證縮容后集群穩定性,我們一般會一個節點一個節點從集群中摘除,那么如何判斷節點是否可以摘除其利用率百分比就是重要的指標。此時如果大規則機器有較低的利用率被判斷縮容,那么很有可能會造成節點縮容后,容器重新調度后的爭搶。如果優先縮容小規則機器,則可能造成縮容后資源的大量冗余。

(2) 機器利用率不單純依靠宿主機計算

在大部分生產環境中,資源利用率都不會保持一個高的水位,但從調度來講,調度應該保持一個比較高的水位,這樣才能保障集群穩定性,又不過多浪費資源。

2 彈性伸縮概念的延伸

不是所有的業務都存在峰值流量,越來越細分的業務形態帶來更多成本節省和可用性之間的跳轉。

(1) 在線負載型:微服務、網站、API (2) 離線任務型:離線計算、機器學習 (3) 定時任務型:定時批量計算 不同類型的負載對於彈性伸縮的要求有所不同,在線負載對彈出時間敏感,離線任務對價格敏感,定時任務對調度敏感。

2.2 kubernetes 彈性伸縮布局

1 在 Kubernetes 的生態中,在多個維度、多個層次提供了不同的組件來滿足不同的伸縮場景

有三種彈性伸縮:

(1) CA(Cluster Autoscaler): Node級別自動擴/縮容cluster-autoscaler組件。 (2) HPA(Horizontal Pod Autoscaler): Pod個數自動擴/縮容。 (3) VPA(Vertical Pod Autoscaler): Pod配置自動擴/縮容,主要是CPU、內存。addon-resizer組件

如果在雲上建議 HPA 結合 cluster-autoscaler 的方式進行集群的彈性伸縮管理。

2 在Kubernetes平台中,資源分為兩個維度 (1) Node級別:K8s將多台服務器抽象一個集群資源池,每個Node提供這些資源 (2) Pod級別:Pod是K8s最小部署單元,運行實際的應用程序,使用request和limit為Pod配額 因此,K8s實現彈性伸縮也是這兩個級別,當Node資源充裕情況下,Pod可任意彈性,當不足情況下需要彈性增加節 點來擴容資源池。 (3) 針對Pod負載:當Pod資源不足時,使用HPA(Horizontal Pod Autoscaler)自動增加Pod副本數量 (4) 針對Node負載:當集群資源池不足時,使用CA(Cluster Autoscaler)自動增加Node

3 Node彈性伸縮有兩種方案 (1) Cluster Autoscaler:是一個自動調整Kubernetes集群大小的組件,需要與公有雲一起使用,例如AWS、Azure、Aliyun 項目地址:https://github.com/kubernetes/autoscaler (2) 自研發:根據Node監控指標或者Pod調度狀態判斷是否增加Node,需要一定開發成本

2.3 Node 自動擴容/縮容

1 Cluster AutoScaler

擴容:Cluster AutoScaler 定期檢測是否有充足的資源來調度新創建的 Pod,當資源不足時會調用 Cloud Provider 創建新的 Node。

cluster-autoscaler-up

縮容:Cluster AutoScaler 也會定期監測 Node 的資源使用情況,當一個 Node 長時間資源利用率都很低時(低於 50%)自動將其所在虛擬機從雲服務商中刪除。此時,原來的 Pod 會自動調度到其他 Node 上面。

cluster-autoscaler-down

Cluster Autoscaler支持的雲提供商(阿里雲、aws、azure ......): https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler/cloudprovider/ GCE:https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/ GKE:https://cloud.google.com/container-engine/docs/cluster-autoscaler/

2 自研發-基於Ansible自動增加Node

ansible-node-scaler

(1) 觸發新增Node (2) 調用Ansible腳本部署組件 (3) 檢查服務是否可用 (4) 調用API將新Node加入集群或者啟用Node自動加入 (5) 觀察新Node狀態 (6) 完成Node擴容,接收新Pod

3 自研發-基於Ansible自動增加Node

(1) 自動增加Node

https://github.com/HyjyLc/ansible-install-k8s/

1)在k8s主節點添加新增節點的解析(kubectl操作節點時使用的是主機名)

# echo '172.16.1.85 k8s-node3' >> /etc/hosts

2)擴容node

# cd /root/ansible-install-k8s-master/
# vim hosts
[newnode]
172.16.1.85 node_name=k8s-node3
注: /root/ansible-install-k8s-master/roles/node/templates/
bootstrap.kubeconfig.j2、kube-proxy.kubeconfig.j2
文件對多master進行了判斷,如果是多master,kubelet、kube-proxy的kubeconfig使用的是VIP,否則則相反。

# ansible-playbook -i hosts add-node.yml -uroot -k
# kubectl get node
# kubectl get pod -n kube-system -o wide

(2) 自動減少Node

如果你想從Kubernetes集群中刪除節點,正確流程如下
1) 獲取節點列表
kubectl get node
2) 設置不可調度
kubectl cordon <node_name>
3) 驅逐節點上的Pod
kubectl drain <node_name> --ignore-daemonsets
4) 移除節點
kubectl delete node <node_name>

注:
如果這塊自動化的話,前提要獲取長期空閑的Node,然后執行這個步驟。
我這里是二進制部署的k8s,在下線的node節點重新啟動kubelet、kube-proxy服務后就可以重新將下線的node節點注冊上了。
如果是kubeadm部署的k8s,需要在master節點上重新生成node加入k8s集群的token即可。

2.4 Pod自動擴容/縮容(HPA)

1 HPA介紹

Horizontal Pod Autoscaler(HPA,Pod水平自動伸縮),根據資源利用率或者自定義指標自動調整replication controller, deployment 或 replica set,實現部署的自動擴展和縮減,讓部署的規模接近於實際服務的負載。HPA不適用於無法縮放的對象,例如DaemonSet。

hpa-1

2 使用HPA前提條件

(1) 使用HPA,確保滿足以下條件 1)啟用Kubernetes API聚合層 2)相應的API已注冊 對於資源指標(例如CPU、內存),將使用metrics.k8s.io API,一般由metrics-server提供。 對於自定義指標(例如QPS),將使用custom.metrics.k8s.io API,由相關適配器(Adapter)服務提供。 已知適配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api

(2) Kubernetes API Aggregation

在 Kubernetes 1.7 版本引入了聚合層,允許第三方應用程序通過將自己注冊到kube-apiserver上,仍然通過 API Server 的 HTTP URL 對新的 API 進行訪問和操作。為了實現這個機制,Kubernetes 在 kube-apiserver 服務中引入了一個 API 聚合層(API Aggregation Layer),用於將擴展 API 的訪問請求轉發到用戶服務的功能。

aggergation

當你訪問 apis/metrics.k8s.io/v1beta1 的時候,實際上訪問到的是一個叫作 kube-aggregator 的代理。而 kube-apiserver,正是這個代理的一個后端;而 Metrics Server,則是另一個后端 。通過這種方式,我們就可以很方便地擴展 Kubernetes 的 API 了。 如果你使用kubeadm部署的,默認已開啟。如果你使用二進制方式部署的話,需要在kube-APIServer中添加啟動參數,增加以下配置:

# vim /opt/kubernetes/cfg/kube-apiserver.conf
......
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
--proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem \
--requestheader-allowed-names=kubernetes \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \
......

在設置完成重啟 kube-apiserver 服務,就啟用 API 聚合功能了。

3 HPA冷卻周期

在彈性伸縮中,冷卻周期是不能逃避的一個話題, 由於評估的度量標准是動態特性,副本的數量可能會不斷波動。有時被稱為顛簸, 所以在每次做出擴容縮容后,冷卻時間是多少。在 HPA 中,默認的擴容冷卻周期是 3 分鍾,縮容冷卻周期是 5 分鍾。 可以通過調整 kube-controller-manager 組件啟動參數設置冷卻時間。 --horizontal-pod-autoscaler-downscale-delay // 擴容冷卻 --horizontal-pod-autoscaler-upscale-delay // 縮容冷卻

4 HPA的演進歷程

目前 HPA 已經支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三個大版本 。 目前大多數人比較熟悉是autoscaling/v1,這個版本只支持CPU一個指標的彈性伸縮。 而autoscaling/v2beta1增加了支持自定義指標,autoscaling/v2beta2又額外增加了外部指標支持。 而產生這些變化不得不提的是Kubernetes社區對監控與監控指標的認識與轉變。從早期Heapster到Metrics Server再到將指標邊界進行划分,一直在豐富監控生態。 (1) autoscaling/v1版本

 
           
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: web
  namespace: lc
spec:
  maxReplicas: 10
  minReplicas: 2
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  targetCPUUtilizationPercentage: 80

(2) autoscaling/v2beta2(多指標)

# kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml

metrics中的type字段有四種類型的值:Object、Pods、Resource、External。 Resource:指的是當前伸縮對象下的pod的cpu和memory指標,只支持Utilization和AverageValue類型的目標值。 Object:指的是指定k8s內部對象的指標,數據需要第三方adapter提供,只支持Value和AverageValue類型的目標值。 Pods:指的是伸縮對象Pods的指標,數據需要第三方的adapter提供,只允許AverageValue類型的目標值。 External:指的是k8s外部的指標,數據同樣需要第三方的adapter提供,只支持Value和AverageValue類型的目標值。

 
           
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

5 資源指標與自定義指標工作流程

image-20211012102418830

(1) 資源指標工作流程: hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor) (2) 自定義資源指標工作流程: hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

2.5 基於CPU資源指標縮放

1 基本工作原理

Kubernetes 中的 Metrics Server 持續采集所有 Pod 副本的指標數據。HPA 控制器通過 Metrics Server 的 API(Heapster 的 API 或聚合 API)獲取這些數據,基於用戶定義的擴縮容規則進行計算,得到目標 Pod 副本數量。當目標 Pod 副本數量與當前副本數量不同時,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)發起 scale 操作,調整 Pod 的副本數量,完成擴縮容操作。

hpa-2

2 部署 Metrics Server

Metrics Server是一個集群范圍的資源使用情況的數據聚合器,作為一個應用部署在集群中。 Metric server從每個節點上Kubelet公開的摘要API(cadvisor)收集指標。 Metrics server通過Kubernetes聚合器注冊在Master APIServer中。

hpa-3

hpa/kubectl get --raw/kubectl top -> apiserver -> metrics-server(不效驗證書) -> kubelet/cadvisor(https自簽)

兼容性:

hpa

(1) 項目地址
https://github.com/kubernetes-sigs/metrics-server/
https://github.com/kubernetes-sigs/metrics-server/releases/
(2) 下載yaml
# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.5.1/components.yaml
(3) 修改yml文件
# vim components.yaml

image-20211011180121661

# 修改的參數如下
- --kubelet-insecure-tls
image: registry.aliyuncs.com/google_containers/metrics-server:v0.5.1
(4) 部署
# kubectl apply -f components.yaml
(5) 查看容器
# kubectl get pod -n kube-system -o wide | grep metrics-server
metrics-server-6f6f7948b9-w98vc 1/1 Running 0 41s 172.27.224.7 k8s-master2

可通過Metrics API在Kubernetes中獲得資源使用率指標,例如容器CPU和內存使用率。這些度量標准既可以由用戶直接訪問(例如,通過使用kubectl top命令),也可以由集群中的控制器(例如,Horizontal Pod Autoscaler)用於進行決策。

(6) 測試
1) 查看注冊到apiserver上的metrics-server
# kubectl get apiservices |grep metrics
v1beta1.metrics.k8s.io kube-system/metrics-server True 23m

2) 獲取node,pod的cpu、內存使用量指標
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods

3) 查看node資源消耗
# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master1 205m 10% 995Mi 25%
k8s-master2 237m 11% 965Mi 25%
k8s-node1 131m 6% 635Mi 16%
k8s-node2 87m 4% 410Mi 10%

4) 查看pod資源消耗(區分命名空間)
# kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
calico-kube-controllers-97769f7c7-fnxpb 1m 13Mi
calico-node-4hngl 25m 65Mi
calico-node-5kwnr 29m 69Mi
calico-node-h46tb 25m 65Mi
calico-node-qchbv 25m 62Mi
coredns-6cc56c94bd-cwtgf 3m 12Mi
metrics-server-6f6f7948b9-fwss4 4m 20Mi

5) 以上測試能正常顯示資源消耗,說明Metrics Server服務工作正常。

3 autoscaling/v1(CPU指標實踐)

autoscaling/v1版本只支持CPU一個指標。


  
  
  
          
(1) 部署應用
# kubectl create namespace lc
# kubectl create deployment web --image=nginx -n lc --dry-run=client -o yaml > deployment-web-lc.yaml

# cat deployment-web-lc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web
  namespace: lc
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          requests:
            memory: "300Mi"
            cpu: "300m"
          limits:
            memory: "450Mi"
            cpu: "450m"
# 注意:修改yaml,增加resources.requests.cpu

# kubectl apply -f deployment-web-lc.yaml

# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort -n lc \
--dry-run=client -o yaml > service-web-lc.yaml

# cat service-web-lc.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
  namespace: lc
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: NodePort

# kubectl apply -f service-web-lc.yaml

(2) 創建HPA
# kubectl autoscale deployment web -n lc --min=2 --max=10 --cpu-percent=80 \
--dry-run=client -o yaml > deployment-web-lc-hpa.yaml

# cat deployment-web-lc-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: web
  namespace: lc
spec:
  maxReplicas: 10
  minReplicas: 2
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  targetCPUUtilizationPercentage: 80
# scaleTargetRef:表示當前要伸縮對象是誰
# targetCPUUtilizationPercentage:當整體的資源利用率超過80%的時候,會進行擴容。

# kubectl apply -f deployment-web-lc-hpa.yaml

# kubectl get hpa -n lc
NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   0%/80%    2         10        2          78s
# 說明:為名為web的deployment創建一個HPA對象,目標CPU使用率為80%,副本數量配置為2到10之間。

(3) 壓測
# yum install httpd-tools
# ab -n 2000000 -c 100 http://172.28.34.23/index.html
# 總200w請求,並發100,172.28.34.23為ClusterIP

(4) 觀察擴容狀態
# kubectl get hpa -n lc
NAME   REFERENCE        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   106%/80%   2         10        8          21m
# 可以看到deployment/web的副本數加到了8,由於node節點cpu的資源不夠了,不能夠繼續創建pod了。

# kubectl top pods -n lc
NAME                   CPU(cores)   MEMORY(bytes)
web-86c68d4466-khvqg   253m         4Mi
web-86c68d4466-ksfkz   221m         5Mi
web-86c68d4466-kwldc   250m         4Mi
web-86c68d4466-ltpbf   258m         7Mi
web-86c68d4466-mbflm   173m         4Mi
web-86c68d4466-mchtg   272m         4Mi
web-86c68d4466-px8cv   262m         4Mi
web-86c68d4466-rsqg4   258m         7Mi

# kubectl get pods -n lc
NAME                   READY   STATUS    RESTARTS   AGE
web-86c68d4466-khvqg   1/1     Running   0          7m31s
web-86c68d4466-ksfkz   1/1     Running   0          11m
web-86c68d4466-kwldc   1/1     Running   0          8m21s
web-86c68d4466-ltpbf   1/1     Running   1          27m
web-86c68d4466-mbflm   1/1     Running   0          7m31s
web-86c68d4466-mchtg   1/1     Running   0          8m21s
web-86c68d4466-px8cv   1/1     Running   0          11m
web-86c68d4466-rsqg4   1/1     Running   1          35m

(5) 關閉壓測,過5分鍾后檢查縮容狀態,發現pod數量變為了2
# kubectl get hpa -n lc
NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   0%/80%    2         10        2          32m

# kubectl get pods -n lc
NAME                   READY   STATUS    RESTARTS   AGE
web-86c68d4466-ltpbf   1/1     Running   1          33m
web-86c68d4466-rsqg4   1/1     Running   1          41m



2.6 基於Prometheus自定義指標縮放

資源指標只包含CPU、內存,一般來說也夠了。但如果想根據自定義指標:如請求qps/5xx錯誤數來實現HPA,就需要使用自定義指標了,目前比較成熟的實現是 Prometheus Custom Metrics。自定義指標由Prometheus來提供,再利用k8s-prometheus-adpater聚合到apiserver,實現和核心指標(metric-server)同樣的效果。 為滿足更多的需求,HPA也支持自定義指標,例如QPS、5xx錯誤狀態碼等,實現自定義指標由autoscaling/v2版本提供,而v2版本又分為beta1和beta2兩個版本。 這兩個版本的區別是autoscaling/v2beta1支持了Resource Metrics(資源指標)、Custom Metrics(自定義指標)。 在autoscaling/v2beta2的版本中額外增加了External Metrics(擴展指標)的支持。 對於自定義指標(例如QPS),將使用custom.metrics.k8s.io API,由相關適配器(Adapter)服務提供。 已知適配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api

hpa-4

hpa/kubectl get --raw/kubectl top -> apiserver -> prometheus-adpater -> prometheus -> pod(自定義暴露指標)

假設我們有一個網站,想基於每秒接收到的HTTP請求對其Pod進行自動縮放,實現HPA大概步驟如下: (1) 部署Prometheus (2) 對應用暴露指標,部署應用,並讓Prometheus采集暴露的指標 (3) 部署Prometheus Adapter (4) 為指定HPA配置Prometheus Adapter (5) 創建HPA (6) 壓測、驗證

1 部署Prometheus

Prometheus(普羅米修斯)是一個最初在SoundCloud上構建的監控系統。自2012年成為社區開源項目,擁有非常活躍的開發人員和用戶社區。為強調開源及獨立維護,Prometheus於2016年加入雲原生雲計算基金會(CNCF),成為繼Kubernetes之后的第二個托管項目。

(1) Prometheus 特點 1)多維數據模型:由度量名稱和鍵值對標識的時間序列數據 2)PromSQL:一種靈活的查詢語言,可以利用多維數據完成復雜的查詢 3)不依賴分布式存儲,單個服務器節點可直接工作 4)基於HTTP的pull方式采集時間序列數據 5)推送時間序列數據通過PushGateway組件支持 6)通過服務發現或靜態配置發現目標 7)多種圖形模式及儀表盤支持(grafana)

(2) Prometheus組成及架構

prometheus-arch

1)Prometheus Server:收集指標和存儲時間序列數據,並提供查詢接口 2)ClientLibrary:客戶端庫 3)Push Gateway:短期存儲指標數據。主要用於臨時性的任務 4)Exporters:采集已有的第三方服務監控指標並暴露metrics 5)Alertmanager:告警 6)Web UI:簡單的Web控制台

(3) 部署(采用deployment方式部署)

# unzip prometheus.zip
# cd prometheus/
# ls -l
prometheus-configmap.yaml # 部署Prometheus
prometheus-deployment.yaml # Prometheus配置文件,主要配置基於Kubernetes服務發現
prometheus-rules.yaml # Prometheus告警規則

# kubectl apply -f .
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
(省略的內容)......
prometheus-8474f8559d-zrpg8 2/2 Running 0 2m19s

# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
(省略的內容)......
prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 2m43s

訪問Prometheus UI: http://NodeIP:30090

2 部署一個應用並暴露Prometheus采集的指標

對應用暴露指標,部署應用,並讓Prometheus采集暴露的指標。在做這步之前先了解下Prometheus如何監控應用的。 如果要想監控,前提是能獲取被監控端指標數據,並且這個數據格式必須遵循Prometheus數據模型,這樣才能識別和采集,一般使用exporter提供監控指標數據。但對於自己開發的項目,是需要自己實現類似於exporter的指標采集程序。 exporter列表:https://prometheus.io/docs/instrumenting/exporters

image-20211012133939633

先模擬自己開發一個網站,采用Python Flask Web框架,寫兩個頁面,/ 首頁,/metrics 指標、然后使用Dockefile制作成鏡像並部署 到Kubernetes平台。


  
  
  
          
# cat metrics-flask-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-flask-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: flask-app
  template:
    metadata:
      labels:
        app: flask-app
      # 聲明Prometheus采集
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
        prometheus.io/path: "/metrics"
    spec:
      containers:
      - image: lc/metrics-flask-app
        name: web
        resources:
          requests:
            memory: "300Mi"
            cpu: "300m"
---
apiVersion: v1
kind: Service
metadata:
  name: metrics-flask-app 
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: flask-app

# kubectl apply -f metrics-flask-app.yaml

(1) flask-app.py
# cat main.py
import prometheus_client
from prometheus_client import Counter
from flask import Response, Flask

app = Flask(__name__)

requests_total = Counter("request_count","統計HTTP請求")

@app.route("/metrics")
def requests_count():
    requests_total.inc()
    return Response(prometheus_client.generate_latest(requests_total),
                    mimetype="text/plain")

@app.route('/')
def index():
    requests_total.inc()
    return "Hello World"

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=80)

(2) Dockerfile
# cat Dockerfile
FROM python
RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/ && \
    pip install prometheus_client -i https://mirrors.aliyun.com/pypi/simple/
COPY main.py /
CMD python main.py



該metrics-app暴露了一個Prometheus指標接口,可以通過訪問service看到

# kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.28.0.1 <none> 443/TCP 23d
metrics-flask-app ClusterIP 172.28.128.88 <none> 80/TCP 10m

# curl 172.28.128.88/metrics
# HELP request_count_total 統計HTTP請求
# TYPE request_count_total counter
request_count_total 9.0
# HELP request_count_created 統計HTTP請求
# TYPE request_count_created gauge
request_count_created 1.63419377682031e+09
# 說明: 由於是svc起到了負載均衡的作用,每次統計到的request_count_total值都不一樣。

由於我們Prometheus配置了基於Kubernetes服務發現,會自動采集Pod暴露的指標,在prometheus UI界面中查看被采集到指標的pod。

image-20211014145243894

image-20211014145415079

3 部署 Custom Metrics Adapter

但是prometheus采集到的metrics並不能直接給k8s用,因為兩者數據格式不兼容,還需要另外一個組件(k8s-prometheus-adpater),將prometheus的metrics 數據格式轉換成k8s API接口能識別的格式,轉換以后,因為是自定義API,所以還需要用Kubernetes aggregator在主APIServer中注冊,以便直接通過/apis/來訪問。

https://github.com/DirectXMan12/k8s-prometheus-adapter 注: 由於官方推薦使用的helm安裝,我在國內拉不下來,我這里直接使用yaml進行不出,yaml也是從helm中拿到的。

(1) prometheus-adapter.yaml配置文件注意點
prometheus-adapter部署在kube-system命名空間下(configmap配置文件在kube-system命名空間),並添加prometheus-adapter連
接prometheus的參數prometheus-url=http://prometheus.kube-system:9090。
(省略內容)......
containers:
- name: prometheus-adapter
image: "directxman12/k8s-prometheus-adapter-amd64:v0.7.0"
imagePullPolicy: IfNotPresent
args:
- /adapter
- --secure-port=6443
- --cert-dir=/tmp/cert
- --logtostderr=true
- --prometheus-url=http://prometheus.kube-system:9090
- --metrics-relist-interval=1m
- --v=4
- --config=/etc/adapter/config.yaml
ports:
(省略內容)......

(2) 部署
# kubectl apply -f prometheus-adapter.yaml

# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
(省略的內容......)
prometheus-8474f8559d-zrpg8 2/2 Running 0 18m
prometheus-adapter-7f94cc997d-qhpcf 1/1 Running 0 50s

# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 172.28.0.2 <none> 53/UDP,53/TCP,9153/TCP 23d
prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 18m
prometheus-adapter ClusterIP 172.28.10.137 <none> 443/TCP 93s

(3) 驗證適配器注冊到APIServer
# kubectl get apiservices |grep custom
v1beta1.custom.metrics.k8s.io kube-system/prometheus-adapter True 3m26s

# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"

4 指定prometheus-adapter從prometheus中查詢指標的配置(configmap)


  
  
  
          
(1) 配置內容配置
# cat prometheus-adapter-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-adapter
  labels:
    app: prometheus-adapter
    chart: prometheus-adapter-2.5.1
    release: prometheus-adapter
    heritage: Helm
  namespace: kube-system
data:
  config.yaml: |
    rules:
    - seriesQuery: 'request_count_total{app="flask-app"}'
      resources:
        overrides:
          kubernetes_namespace: {resource: "namespace"}
          kubernetes_pod_name: {resource: "pod"}
      name:
        matches: "request_count_total"
        as: "qps"
      metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'

(2) 配置說明
seriesQuery        # Prometheus查詢語句,查詢應用系列指標。
resources        # Kubernetes資源標簽映射到Prometheus標簽。
name            # 將Prometheus指標名稱在自定義指標API中重命名,
matches            # 正則匹配,as指定新名稱。
metricsQuery    # 一個Go模板,對調用自定義指標API轉換為Prometheus查詢語句。

(3) 應用配置
# kubectl apply -f prometheus-adapter-configmap.yaml
# 刪除prometheus-adapter pod使配置生效
# kubectl delete pod/prometheus-adapter-7f94cc997d-qhpcf -n kube-system

(4) 向自定義指標API訪問
# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/qps"
注: 如果配置沒問題,會返回JSON數據,注意里面的value字段,HPA控制器會拿這個值計算然后比對閾值。這個值單位是m,表示毫秒,千分之一,
例如值為500m是每秒0.5個請求,10000m是每秒10個請求(並發)。
Adapter向Prometheus查詢語句最終是由於HTTP請求統計是累計的,對HPA自動縮放不是特別有用,因此將其轉為速率指標。
這條語句意思是:查詢每個Pod在2分鍾內訪問速率,即QPS(每秒查詢率)
sum(rate(request_count_total{app="flask-app", kubernetes_namespace="default", kubernetes_pod_name=~"pod1|pod2"}[2m])) by (kubernetes_pod_name)



image-20211014150750015

image-20211014151407702

5 創建HPA策略


  
  
  
          
# cat hpa-v2-qps.yaml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: metrics-flask-app
  namespace: default
spec:
  minReplicas: 1
  maxReplicas: 10
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: metrics-flask-app
  metrics:
  - type: Pods
    pods:
      metric:
        name: qps
      target:
        type: AverageValue
        averageValue: 10000m
# 所有Pod平均值為10000m觸發擴容,即每秒10個請求

# kubectl apply -f hpa-v2-qps.yaml
# kubectl get hpa -n default
NAME                REFERENCE                      TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
metrics-flask-app   Deployment/metrics-flask-app   16m/10    1         10        3          41s



6 壓測

# yum install httpd-tools -y
# ab -n 100000 -c 100 http://172.28.128.88/
# 172.28.128.88 是 deployment/metrics-flask-app svc 的 cluster-ip 地址

7 查看HPA狀態

# 可以看到pod副本數擴充到了10個
# kubectl get hpa -n default
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
metrics-flask-app Deployment/metrics-flask-app 202072m/10 1 10 10 4m17s

# kubectl get pod -n default
NAME READY STATUS RESTARTS AGE
metrics-flask-app-5475d5f794-4n9sw 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-6cm4c 1/1 Running 0 2m26s
metrics-flask-app-5475d5f794-9gwzp 1/1 Running 0 80m
metrics-flask-app-5475d5f794-9jlt2 1/1 Running 0 2m26s
metrics-flask-app-5475d5f794-chwrl 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-gnvm7 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-jvl26 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-lnj4q 1/1 Running 0 80m
metrics-flask-app-5475d5f794-px6pg 1/1 Running 0 80m
metrics-flask-app-5475d5f794-ws42t 1/1 Running 0 2m26s

# kubectl describe hpa metrics-flask-app



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM