Kubernetes高級進階之pod的自動擴容/縮容

目錄:
實踐1:基於autoscaling cpu指標的擴容與縮容
實踐2:基於prometheus自定義指標QPS的擴容與縮容

                           Pod自動擴容/縮容(HPA)
Horizontal Pod Autoscaler(HPA,Pod水平自動伸縮),根據資源利用率或者自定義指標自動調整replication controller, deployment 或 replica set,實現部署的自動擴展和縮減,讓部署的規模接近於實際服務的負載。HPA不適於無法縮放的對象,例如DaemonSet。
HPA主要是對pod資源的一個計算,對當前的副本數量增加或者減少。
HPA大概是這樣的,我們需要創建一個hpa的規則,設置這樣的一個規則對pod實現一個擴容或者縮容,主要針對deployment,當你當前設置的資源利用率超出你設置的預值,它會幫你擴容縮容這些副本。

Kubernetes高級進階之pod的自動擴容/縮容
1、HPA基本原理
Kubernetes 中的 Metrics Server 持續採集所有 Pod 副本的指標數據。HPA 控制器通過 Metrics Server 的 API(Heapster 的 API 或聚合 API)獲取這些數據,基於用戶定義的擴縮容規則進行計算,得到目標 Pod 副本數量。當目標 Pod 副本數量與當前副本數量不同時,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)發起 scale 操作,調整 Pod 的副本數量,完成擴縮容操作。如圖所示。
Kubernetes高級進階之pod的自動擴容/縮容
在彈性伸縮中,冷卻週期是不能逃避的一個話題, 由於評估的度量標準是動態特性,副本的數量可能會不斷波動。有時被稱爲顛簸, 所以在每次做出擴容縮容後,冷卻時間是多少。

來看這張圖,首先hpa要創建一個規則,就像我們之前創建ingress的規則一樣,裏面定義好一個擴容縮容的一個範圍然後指定好對象,指定好它的預值,hpa本身就是一個控制器,循環的控制器,它會不斷的從metrics server 中去獲取這個指標,判斷這個預值是不是到達你設置規則的預值,如果是的話,就會去執行這個scale幫你擴容這個副本,如果長期處於一個低使用率的情況下,它會幫你縮容這個副本,這個metrics server的資源來源是來自於cadvisor去拿的,想一下cadvisor可以提供那些指標,hpa可以拿到的,比如cpu,內存的使用率,主要採集你這些的利用率,所以hpa在早期已經支持了對CPU的彈性伸縮

Hpa就是k8s中這個pod水平擴容的一個控制器,但是要實現
Pod的擴容,他需要一定的條件,他要拿一定的指標,這裏是有預值的,他要判斷你的指標,是不是超出這個預值,對你進行縮容擴容,所以要想得到這個指標,你還需要裝一個組件,metrics server,在之前呢這個組件的實現是由heapster heapstar現在已經是慢慢棄用了,基本上不怎麼去使用heapstat了,所以metrics server來提供這些數據,提供這些資源的利用率。

比如有三個副本,來實現三個pod的伸縮,所以有東西去判定資源的利用率,比如基於cpu的,計算3個pod的資源利用率,例如3個pod的資源利用率是50%,拿到這個值之後,你就要去使用這個hpa,這個裏面會定義個預值,有個規則,這個預值設置60%,它會週期性的與cpu去匹配,如果超出這個60%,那麼就去擴容,這裏還有定義擴容pod副本的數量
比如我這組pod的訪問量是異常的,比如受到一些小***,我的cpu就超過50%,如果沒有限制去最大擴容到多大的副本,它會無限的增大,之前3個副本可能一下就增加了10個副本,甚至50個,那麼很快就能拖死整個集羣,所以在hpa中都設置3個指標,第一個設置,pod的區間值,這個最大能擴容多少個pod,最小是多少個pod,比如1-10,最小可以創建1個,最大可以創建10個,這是一個縮容擴容的一個範圍值,接下來就是一個預值的判斷,第三個就是操作哪個對象,哪一組pod,這三個都是要在hpa中去判斷的

那麼在什麼情況下,去縮容擴容
擴容就是資源不夠了超過這個60%了,但是在這個區間它是由個狀態轉化的,一個是擴容的狀態,一個是縮容的狀態,這兩個狀態就好比現在的資源利用率60%了,進行擴容了,有3個副本就擴容到10個副本了,這是沒問題的,然後馬上這個值下來了,之前是到了70%-80%了,現在一下到了20%,從10直接縮容到5個,這兩個是有狀態轉化的,所以hpa得基於保證說不可能狀態轉化的區間頻率太高,如果太高就會出現好比時好時壞,間歇性的突發,並不是一直的突發,它會導致一會擴一會縮,最後導致這個應用不穩定,所以hpa就有一個冷卻的機制,第一次擴容之後,第二次要想擴容必須經過這個冷卻時間,那麼默認是3分鐘,縮容呢,第一次後,第二次縮容要等5分鐘之後,這就是一個默認的一個值,來保障你當前業務的穩定性,是通過kube-controller-manager組件啓動參數設置的

在 HPA 中,默認的擴容冷卻週期是 3 分鐘,縮容冷卻週期是 5 分鐘。
可以通過調整kube-controller-manager組件啓動參數設置冷卻時間:

•   --horizontal-pod-autoscaler-downscale-delay :擴容冷卻
•   --horizontal-pod-autoscaler-upscale-delay :縮容冷卻

2、HPA的演進歷程
目前 HPA 已經支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三個大版本 。
目前大多數人比較熟悉是autoscaling/v1,這個版本只支持CPU一個指標的彈性伸縮。
這個也比較簡單,創建一個規則,使用採集的組件就能用了,

而autoscaling/v2beta1增加了支持自定義指標,除了cadvisor暴露的指標外,還支持自定義指標,比如像第三方提供的QPS,或者基於其他的一些資源進行擴容,就是支持一些第三方的一些組件了。
autoscaling/v2beta2又額外增加了外部指標支持。
而產生這些變化不得不提的是Kubernetes社區對監控與監控指標的認識認識與轉變。從早期Heapster到Metrics Server再到將指標邊界進行劃分,一直在豐富監控生態。
所以有這些指標的變化,k8s對監控的認識進行了轉變,因爲彈性伸縮,在k8s中含金量還是比較高的,之前是沒有太好的方案,所以在這一塊也不是應用很多,然後再到社區對這一塊進行完善,現在應用的也逐漸增多了。
實例
V1版本就是一個cpu的一個限制,其實早期也會內存也進行開放,後期只針對cpu進行了限制,因爲只暴露cpu,是因爲暴露內存並不是使用彈性伸縮的一個指標,因爲像一個內存都會有一些應用去管理,比如java,內存都是有一個jvm去管理,所以使用內存擴容的一個指標,並不是很好,所以只暴露了cpu的指標,cpu還是比較準確的,pod,cpu利用率上來之後,負載高了,流量高了,所以這塊參考價值比較大的,所以只使用cpu,在這裏指定一個百分比就行。

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版本
就支持了很多的自定義的東西,比如resource,pods.object,external
可以根據cpu做一些pod暴露指標方面的工作,也可以針對第三方的一些指標,還有一些第三方的指標,像消息隊列之類的,
V2支持的更多了

2.5 基於CPU指標縮放
1、 Kubernetes API Aggregation
在 Kubernetes 1.7 版本引入了聚合層,允許第三方應用程序通過將自己註冊到kube-apiserver上,仍然通過 API Server 的 HTTP URL 對新的 API 進行訪問和操作。爲了實現這個機制,Kubernetes 在 kube-apiserver 服務中引入了一個 API 聚合層(API Aggregation Layer),用於將擴展 API 的訪問請求轉發到用戶服務的功能。
Kubernetes高級進階之pod的自動擴容/縮容
要使用v1版本基於cpu指標縮放,首先要開啓API的聚合,在k8s1.7版本中去引入的,它引入是想讓第三方的應用程序註冊進來,都能註冊到api中,去訪問這個api時就能調用這個組件了,這張圖,首先api的聚合時從API server去啓用的,上面當作API server ,下面當作組件,APIserver它本身就是以後端聚合層後面的,只不過它都在這個裏面實現了,實際上apiserver在聚合層後面,可以把聚合層當作一個代理層,就像nginx代理web一樣,代理的話就可以代理多個了,就不侷限於apiserver了,像metrics server,自己開發的一個組件也能註冊進來,然後讓他代理,它代理之後就可以訪問api,從而訪問到這個組件了,那麼聚合層就像請求的url幫你轉發到後面的組件上,後面的組件都會對應api,根據註冊到聚合層的api轉發,簡而言之就是擴展api的功能,就是方便自己開發的組件,集成到這個api裏面,就像調用api一樣調用你的組件,其實這就是一個聚合層的目的,在k8s中如果使用kubeadm部署的,默認的聚合層已經是啓用了,如果是二進制的部署方式去部署的,那麼要按二進制的方式去啓動聚合層,這個根據自己的環境去啓動,因爲每個人部署的二進制都不一樣。
需要在kube-APIServer中添加啓動參數,增加以下配置:

vi /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 \
...

第一行指定的根證書,就是訪問聚合層也要有一定的認證,不是誰的都能訪問,本身也有一定的安全機制存在,也就是一個可信任的ca
第二,三行代理的是客戶端的證書,大致的意思是放在聚合層進行認證的,來判斷你是否有機制來訪問
第四行的就是允許的名稱,這個是提供的證書裏面的,來判段這個名稱是不是能夠訪問,這個我使用的是apiserver的證書,也可以使用ca單獨爲這個生成一個新的證書
第五行,請求頭來判斷是否可以訪問
第六行,就是啓動聚合層的路由
重啓這個字段
[root@k8s-master1 ~]# vim /opt/kubernetes/cfg/kube-apiserver.conf
將開始聚合層的配置添加進入

[root@k8s-master1 ~]# systemctl restart kube-apiserver
[root@k8s-master1 ~]# ps -ef |grep kube-apiserver

2、部署 Metrics Server
Metrics Server是一個集羣範圍的資源使用情況的數據聚合器。作爲一個應用部署在集羣中。
Metric server從每個節點上Kubelet公開的摘要API收集指標。
Metrics server通過Kubernetes聚合器註冊在Master APIServer中。
它必須能拿到cpu的利用率,有這個才能做對比,要不要擴容,所以要部署一個metrics server到集羣中,讓它爲hpa提供CPU的數據查詢,metrics server相當於一個聚合器,它那的數據就是cadvisor 的數據,它將那些數據每個節點的數據進行聚合,這是它說做的事,因爲你要擴容,並不是一個副本去擴容,並不是參考一個副本的指標,要參考你當前跑的pod的都要考慮,而每個上面都有cadvisor,那訪問當前的pod,就只訪問到當前的利用率,而cadvisor也沒有什麼聚合的作用,要想對所有的pod的資源利用率做一個彙總,那麼上面就有這個metrics server了,之前是有heapstar去做的,現在是由metrics server去做的,幫你去彙總,然後hpa從這個彙總信息裏去拿整體cpu的利用率來判斷這個域,所以metrics server就是一個聚合器,
而且還會從每個節點上kubelet收集這些指標,並通過k8s聚合器註冊在k8s中的apiserver中,所以metrics必須啓動聚合器,所以metrics就能主動的將自己註冊進去,註冊進去之後就可以metrics暴露的一個名稱來請求metrics,會根據你攜帶的名稱幫你轉發到後面的metrics的pod

git clone https://github.com/kubernetes-incubator/metrics-server
cd metrics-server/deploy/1.8+/
vi metrics-server-deployment.yaml   # 添加2條啓動參數   
...
      containers:
      - name: metrics-server
        image: zhaocheng172/metrics-server-amd64:v0.3.1
        command:
        - /metrics-server
        - --kubelet-insecure-tls
        - --kubelet-preferred-address-types=InternalIP
...

確保pod起來

 [root@k8s-master1 1.8+]# kubectl get pod -n kube-system
NAME                              READY   STATUS    RESTARTS   AGE
coredns-59fb8d54d6-7rmx2          1/1     Running   0          43m
kube-flannel-ds-amd64-4jjmm       1/1     Running   0          43m
kube-flannel-ds-amd64-9f9vq       1/1     Running   0          43m
kube-flannel-ds-amd64-gcf9s       1/1     Running   0          43m
metrics-server-64499fd8c6-xkc6c   1/1     Running   0          61s

部署起來先看看metrics-server有沒有正常工作,先看一下pod有沒有錯誤日誌,再看看有沒有註冊到聚合層
通過kubectl get apiservers,查看有沒有註冊到,這裏爲true纔算正常

[root@k8s-master1 1.8+]# kubectl get apiservices
v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        19s

然後查看kubectl top node來查看node資源的利用率

[root@k8s-master1 1.8+]# kubectl top node
NAME          CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
k8s-master1   517m         25%    1021Mi          62%       
k8s-node1     994m         49%    551Mi           33%       
k8s-node2     428m         10%    2466Mi          32%  

也可以通過kubectl top pod來查看pod的資源利用率

[root@k8s-master1 1.8+]# kubectl top pod -n kube-system
NAME                              CPU(cores)   MEMORY(bytes)   
coredns-59fb8d54d6-7rmx2          13m          14Mi            
kube-flannel-ds-amd64-4jjmm       15m          23Mi            
kube-flannel-ds-amd64-9f9vq       7m           15Mi            
kube-flannel-ds-amd64-gcf9s       9m           15Mi            
metrics-server-64499fd8c6-xkc6c   3m           14Mi /

也可以通過metrics api 的標識來獲得資源使用率的指標,比如容器的cpu和內存使用率,這些度量標準既可以由用戶直接訪問,通過kubectl top命令,也可以由集羣中的控制器pod autoscaler用於進行查看,hpa獲取這個資源利用率的時候它是通過接口的,它請求的接口就是api,所以也可以根據api去獲取這些數據,
測試:可以獲取這些數據,這些數據和top看到的都是一樣的,只不過這個是通過api 去顯示的,只不過是通過json去顯示的

kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
[root@k8s-master1 1.8+]# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[{"metadata":{"name":"k8s-master1","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-master1","creationTimestamp":"2019-12-12T03:45:06Z"},"timestamp":"2019-12-12T03:45:03Z","window":"30s","usage":{"cpu":"443295529n","memory":"1044064Ki"}},{"metadata":{"name":"k8s-node1","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-node1","creationTimestamp":"2019-12-12T03:45:06Z"},"timestamp":"2019-12-12T03:45:00Z","window":"30s","usage":{"cpu":"285582752n","memory":"565676Ki"}},{"metadata":{"name":"k8s-node2","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k8s-node2","creationTimestamp":"2019-12-12T03:45:06Z"},"timestamp":"2019-12-12T03:45:01Z","window":"30s","usage":{"cpu":"425912654n","memory":"2524648Ki"}}]}

將命令行輸出的格式轉換成json格式----jq命令
[root@k8s-master1 1.8+]# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes |jq

3、 autoscaing/v1 ( cpu指標實踐 )
autoscaling/v1版本只支持CPU一個指標。
首先部署一個應用並指出一個service,我們一會測試一下進行流量壓測,cpu達到60%的預值然後就進行自動擴容副本,如果流量下來,然後就進行自動的縮容

[root@k8s-master1 hpa]# cat app.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 5
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          requests:
            cpu: 90m
            memory: 90Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

創建HPA策略
用命令生成
kubectl autoscale –help
這裏可以查看到使用的命令用-o yaml輸出出來—dry-run過濾空的字段

 kubectl autoscale deployment foo --min=2 --max=10
 kubectl autoscale deployment nginx --min=2 --max=10 -o yaml  --dry-run > hpa-v1.yaml
[root@k8s-master1 hpa]# cat hpa-v1.yaml 
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx
spec:
  maxReplicas: 6
  minReplicas: 3
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  targetCPUUtilizationPercentage: 60
scaleTargetRef:表示當前要伸縮對象是誰
targetCPUUtilizationPercentage:當整體的資源利用率超過60%的時候,會進行擴容。
Maxreplicas:是最大擴容到的副本量
Minreplicas:是最小縮容到的副本量

查看擴容狀態

[root@k8s-master1 hpa]# kubectl get hpa
NAME    REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx   Deployment/nginx   0%/60%    3         6         3          52m

開啓壓測,進行對我們的cluster IP進行測試

[root@k8s-master1 hpa]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   5h20m
nginx        ClusterIP   10.0.0.211   <none>        80/TCP    48m

安裝壓測命令

yum install httpd-tools -y
[root@k8s-master1 hpa]# ab -n 1000000 -c 10000  http://10.0.0.211/index.html

測試cpu已經成功超出預值

[root@k8s-master1 hpa]# kubectl get hpa
NAME    REFERENCE          TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
nginx   Deployment/nginx   148%/60%   3         6         6          56m

最大的副本量是6個,現在已經成功自動擴容

[root@k8s-master1 hpa]# kubectl get pod 
NAME                    READY   STATUS    RESTARTS   AGE
nginx-969bfd4c9-g4zkc   1/1     Running   0          34m
nginx-969bfd4c9-hlcmc   1/1     Running   0          51s
nginx-969bfd4c9-mn2rd   1/1     Running   0          52m
nginx-969bfd4c9-rk752   1/1     Running   0          34m
nginx-969bfd4c9-zmmd8   1/1     Running   0          51s
nginx-969bfd4c9-zz5gp   1/1     Running   0          51s

關閉壓測,過一會大概5分鐘之後就會自動的縮容。

[root@k8s-master1 hpa]# kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-969bfd4c9-g4zkc   1/1     Running   0          39m
nginx-969bfd4c9-mn2rd   1/1     Running   0          57m
nginx-969bfd4c9-rk752   1/1     Running   0          39m
工作流程:hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)

4、autoscaling/v2beta2(多指標)
爲滿足更多的需求, HPA 還有 autoscaling/v2beta1和 autoscaling/v2beta2兩個版本。
這兩個版本的區別是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(應用程序指標),而在 autoscaling/v2beta2的版本中額外增加了 External Metrics的支持。
爲了滿足更多的需求,hpa還有v2beat1和v2beat2兩個版本,這個跨度也比較大,這個可以實現自定義指標

[root@k8s-master1 hpa]# kubectl get hpa.v2beta2.autoscaling -o yaml > hpa-v2.yaml
apiVersion: v1
items:
- apiVersion: autoscaling/v2beta2
  kind: HorizontalPodAutoscaler
  metadata:
    name: nginx
    namespace: default
  spec:
    maxReplicas: 6
    minReplicas: 3
    metrics:
    - resource:
        name: cpu
        target:
          averageUtilization: 60
          type: Utilization
      type: Resource
    scaleTargetRef:
      apiVersion: apps/v1
      kind: Deployment
      name: nginx

與上面v1版本效果一樣,只不過這裏格式有所變化。
v2還支持其他另種類型的度量指標,:Pods和Object。

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: 2k

metrics中的type字段有四種類型的值:Object、Pods、Resource、External。
• Resource:指的是當前伸縮對象下的pod的cpu和memory指標,只支持Utilization和AverageValue類型的目標值。

• Object:指的是指定k8s內部對象的指標,數據需要第三方adapter提供,只支持Value和AverageValue類型的目標值。

• Pods:指的是伸縮對象Pods的指標,數據需要第三方的adapter提供,只允許AverageValue類型的目標值。另外就是pod暴露的指標,比如http的請求數,吞吐量,也就是http它本身暴露的出來的,但是暴露出來,它不能拿到這些指標,還需要藉助一些第三方的監控,也就是使用hpa這裏面值的判斷,這個提前是要通過kubectl apiservices裏面看到註冊進去,到聚合層,所有的hpa都是通過聚合層去拿到的,它其實是請求的api到聚合層,然後聚合層幫你代理到後面的組件,比如像metics-service ,它去幫你拿的,然後每個kubelet幫你收集的(cadvisor每個pod的資源利用率,它幫你做一個聚合,聚合之後通過聚合器暴露出來,然後來查詢設定的pod的資源利用率,並且做了一個平均,這樣就能通過hpa就能拿到之後的目標值,然後hpa再幫你判斷,是否達到這個預值,到的話,幫你擴容。
基於pod的實例,pod本身暴露的指標,比較吞吐量,qps,如果目標是1k也會觸發
Hpa ->apiserver->agg->聚合層->prometheus-adapter然後它註冊到聚合層裏面來,prometheus本身就是一個監控系統,它能採集到所有pod暴露的指標,自己存儲起來,並且展示,adapter主要將自己註冊到聚合層裏面並且它能轉換這個監控指標apiserver相應的數據接口和prometheus的接口是不一樣的,adapter在這裏存在的關鍵是數據格式的轉化,對接的不單純的是prometheus或者其他的監控系統,要想實現自定義指標完成數據的轉化和註冊,然後prometheus將每個pod展示出來

• External:指的是k8s外部的指標,數據同樣需要第三方的adapter提供,只支持Value和AverageValue類型的目標值。
• 工作流程:hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

2.6 基於Prometheus自定義指標縮放
資源指標只包含CPU、內存,一般來說也夠了。但如果想根據自定義指標:如請求qps/5xx錯誤數來實現HPA,就需要使用自定義指標了,目前比較成熟的實現是 Prometheus Custom Metrics。自定義指標由Prometheus來提供,再利用k8s-prometheus-adpater聚合到apiserver,實現和核心指標(metric-server)同樣的效果。

資源一般就包含cpu、內存就夠了,像公有云也是一樣都是基於cpu、內存保守型的維度來實現的,但是我們可能會有一些特殊額需求,比如web的服務請求的QPS,或者這組web提供的這組數據,這也是很常見的需求,不過這類需求,並不是很多,它實現沒那麼簡單,目前很成熟的方案就是用prometheus來自定義這些指標

它大概的流程是這樣的,api adapter註冊到apiserver中的通過apiservice就可以看到,然後到prometheus,然後從pod中獲取到這些指標
Kubernetes高級進階之pod的自動擴容/縮容

1、部署Prometheus
Prometheus(普羅米修斯)是一個最初在SoundCloud上構建的監控系統。自2012年成爲社區開源項目,擁有非常活躍的開發人員和用戶社區。爲強調開源及獨立維護,Prometheus於2016年加入雲原生雲計算基金會(CNCF),成爲繼Kubernetes之後的第二個託管項目。
Prometheus 特點:
• 多維數據模型:由度量名稱和鍵值對標識的時間序列數據
• PromSQL:一種靈活的查詢語言,可以利用多維數據完成複雜的查詢
• 不依賴分佈式存儲,單個服務器節點可直接工作
• 基於HTTP的pull方式採集時間序列數據
• 推送時間序列數據通過PushGateway組件支持
• 通過服務發現或靜態配置發現目標
• 多種圖形模式及儀表盤支持(grafana)
Prometheus組成及架構
Kubernetes高級進階之pod的自動擴容/縮容
• Prometheus Server:收集指標和存儲時間序列數據,並提供查詢接口
• ClientLibrary:客戶端庫
• Push Gateway:短期存儲指標數據。主要用於臨時性的任務
• Exporters:採集已有的第三方服務監控指標並暴露metrics
• Alertmanager:告警
• Web UI:簡單的Web控制檯
部署:
這裏沒有詳細說prometheus的部署,要是需要就看我前面一篇發表的文章
這裏只需要部署一個服務端就可以,可以拿到pod的數據就可以,這裏還有個pv的自動供給,所以這裏我提前部署好了,之前的文章我都寫過,這裏不做過多演示,

[root@k8s-master1 prometheus]# kubectl get pod,svc -n kube-system
NAME                                  READY   STATUS    RESTARTS   AGE
pod/coredns-59fb8d54d6-7rmx2          1/1     Running   0          25h
pod/grafana-0                         1/1     Running   0          18m
pod/kube-flannel-ds-amd64-4jjmm       1/1     Running   0          25h
pod/kube-flannel-ds-amd64-9f9vq       1/1     Running   0          25h
pod/kube-flannel-ds-amd64-gcf9s       1/1     Running   0          25h
pod/metrics-server-64499fd8c6-xkc6c   1/1     Running   0          24h
pod/prometheus-0                      2/2     Running   0          23m

NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
service/grafana          NodePort    10.0.0.233   <none>        80:30007/TCP     18m
service/kube-dns         ClusterIP   10.0.0.2     <none>        53/UDP,53/TCP    25h
service/metrics-server   ClusterIP   10.0.0.67    <none>        443/TCP          24h
service/prometheus       NodePort    10.0.0.115   <none>        9090:30090/TCP   23m

訪問我的prometheus的30090,這裏我沒有部署node節點上的node_experiod的組件所以沒有採集到,這個因爲用不到,我前面的文章部署有詳細說明,這裏不做這個
Kubernetes高級進階之pod的自動擴容/縮容
3、基於QPS指標實踐
部署一個應用:

 [root@k8s-master1 hpa]# cat hpa-qps.yaml 
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: zhaocheng172/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-app暴露了一個Prometheus指標接口,可以通過訪問service看到:

[root@k8s-master1 hpa]# curl 10.0.0.107/metrics
HELP http_requests_total The amount of requests in total
TYPE http_requests_total counter

http_requests_total 31。這一塊是我這個pod總共請求了多少的訪問,累計值
HELP http_requests_per_second The amount of requests per second the latest ten seconds
TYPE http_requests_per_second gauge
http_requests_per_second 0.5 這個是10秒之內的吞吐率,也就是有0.5個http請求,吞吐率和qps是不一樣的概念,qps是指一個範圍內求的一個量,但是他們都是求當前量化的一個指標
現在去查看prometheus有沒有請求到那三個pod的數據
通過http_requests_total,可以看到我們在yaml中去定義的name_app: metrics-app
Kubernetes高級進階之pod的自動擴容/縮容
之前的如果也想被prometheus採集到,那麼就需要去暴露這個指標,這是其一,其二就是採集這個指標,所有的pod的數據是通過yaml中的註解去實現的
app: metrics-app
annotations:
prometheus.io/scrape: "true"。讓它能夠採集
prometheus.io/port: "80"。 訪問它的地址也就是url
prometheus.io/path: "/metrics"。 默認都是metrics
這三個註解的字段都是prometheus開頭的,所以要把這個指標拿走監控起來
Prometheus會掃描k8s中的pod有沒有暴露的指標,有的話,它會自動加入被監控端,然後將暴露出來,所以這就是prometheus對k8s的自動發現所能感知所監控到
現在採集到了然後就是部署custom metrics adapter
部署 Custom Metrics Adapter
但是prometheus採集到的metrics並不能直接給k8s用,因爲兩者數據格式不兼容,還需要另外一個組件(k8s-prometheus-adpater),將prometheus的metrics 數據格式轉換成k8s API接口能識別的格式,轉換以後,因爲是自定義API,所以還需要用Kubernetes aggregator在主APIServer中註冊,以便直接通過/apis/來訪問。
這個主要作用就是將自己註冊到api-server中,第二就是轉換成api可以識別的數據,
https://github.com/DirectXMan12/k8s-prometheus-adapter
該 PrometheusAdapter 有一個穩定的Helm Charts,我們直接使用。
先準備下helm環境:

[root@k8s-master1 helm]# wget https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
[root@k8s-master1 helm]# tar xf helm-v3.0.0-linux-amd64.tar.gz
[root@k8s-master1 helm]# mv linux-amd64/helm /usr/bin

現在就可以使用helm 了,安裝好helm,還能配置一個helm的倉庫
也就是它將adapter存放到這個倉庫裏面了
添加的話建議使用微軟雲的adapter的

[root@k8s-master1 helm]# helm repo add stable http://mirror.azure.cn/kubernetes/charts
"stable" has been added to your repositories
[root@k8s-master1 helm]# helm repo ls
NAME    URL                                     
stable  http://mirror.azure.cn/kubernetes/charts

這樣的話,我們就能使用helm install,安裝adapter了
因爲adapter這個chart比如它要連接prometheus的地址,就是默認的chart並不能之前使用,還得把它改了,所以要指定它的地址和端口,直接通過set命令來替換chart默認的變量
部署prometheus-adapter,指定prometheus地址:

[root@k8s-master1 helm]# helm install prometheus-adapter stable/prometheus-adapter --namespace kube-system --set prometheus.url=http://prometheus.kube-system,prometheus.port=9090
NAME: prometheus-adapter
LAST DEPLOYED: Fri Dec 13 15:22:42 2019
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
prometheus-adapter has been deployed.
In a few minutes you should be able to list metrics using the following command(s):

  kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1
[root@k8s-master1 helm]# helm list -n kube-system
NAME                NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                       APP VERSION
prometheus-adapter  kube-system 1           2019-12-13 15:22:42.043441232 +0800 CST deployed    prometheus-adapter-1.4.0    v0.5.0  

查看pod已經部署成功

[root@k8s-master1 helm]# kubectl get pod -n kube-system
NAME                                  READY   STATUS    RESTARTS   AGE
coredns-59fb8d54d6-7rmx2              1/1     Running   0          28h
grafana-0                             1/1     Running   0          3h30m
kube-flannel-ds-amd64-4jjmm           1/1     Running   0          28h
kube-flannel-ds-amd64-9f9vq           1/1     Running   0          28h
kube-flannel-ds-amd64-gcf9s           1/1     Running   0          28h
metrics-server-64499fd8c6-xkc6c       1/1     Running   0          27h
prometheus-0                          2/2     Running   0          3h35m
prometheus-adapter-77b7b4dd8b-9rv26   1/1     Running   0          2m36s

檢查判斷pod是否工作正常,這裏已經是註冊到聚合層了

[root@k8s-master1 helm]# kubectl get apiservice
v1beta1.custom.metrics.k8s.io          kube-system/prometheus-adapter   True        13m

這樣就能通過一個原始的url去測試這個接口能不能用
[root@k8s-master1 helm]# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" |jq
創建hpa策略

[root@k8s-master1 hpa]# cat hpa-v5.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

查看創建成功的狀態,目前是沒有拿到這個值的。因爲適配器還不知道你要什麼指標(http_requests_per_second),HPA也就獲取不到Pod提供指標。
ConfigMap在default名稱空間中編輯prometheus-adapter ,並seriesQuery在該rules: 部分的頂部添加一個新的:

[root@k8s-master1 hpa]# kubectl get hpa
NAME              REFERENCE          TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
metrics-app-hpa   Deployment/QPS     <unknown>/800m   3         6         0          16m
nginx             Deployment/nginx   0%/60%           3         6         3          24h

添加新的字段,來收集我們想實現的QPS的值
[root@k8s-master1 hpa]# kubectl edit cm prometheus-adapter -n kube-system
將這一塊放到rules下,,而且中間這個其實是promsql,這個可以執行的,而且和我們的之前輸出的結果是一樣的,{裏面表示字段不爲空,更精確一些},這個主要是查詢出一系列數據,下面一段是管聯,將ns和pod關聯,來拿數據,都是對應的關係。
和前面的一樣,只不過前面的是http的訪問的累計值,現在我們要轉換成一個速率,QPS的值是通過範圍之內,1分鐘之內採集了多少指標進行相加,再除以60秒,就是每秒的值, matches: "^(.*)_total",也舉手匹配前面的值進行替換,來提供 as: "${1}_per_second"的值,也就是QPS的值,用這個值爲http提供接口,

    rules:
    - 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>>)'

Kubernetes高級進階之pod的自動擴容/縮容

這個值是求的它的一個平均值,也就是2分鐘之內0.42http請求,每一次執行就就近執行的平均數
rate(http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}[2m])
Kubernetes高級進階之pod的自動擴容/縮容

因爲我們是多個pod,所以我們需要相加對外提供一個指標,然後我們再給一個by,給個標籤,這樣的話進行標籤去查詢
sum(rate(http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}[2m]))
Kubernetes高級進階之pod的自動擴容/縮容
使用by,定義標籤的名稱方便去查詢
sum(rate(http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}[2m])) by (kubernetes_pod_name)
Kubernetes高級進階之pod的自動擴容/縮容

測試api
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second"

目前已經收到我們的值了

NAME              REFERENCE                TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
metrics-app-hpa   Deployment/metrics-app   416m/800m   1         10        3          2m13s
nginx             Deployment/nginx         0%/60%      3         6         3          25h

壓測

Kubectl get svc
metrics-app   ClusterIP   10.0.0.107   <none>        80/TCP    3h15m
ab -n 100000 -c 100  http://10.0.0.107/metrics

查看擴容狀態

[root@k8s-master1 hpa]# kubectl get hpa
NAME              REFERENCE                TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
metrics-app-hpa   Deployment/metrics-app   414m/200m   1         10        10         8m36s
nginx             Deployment/nginx         0%/60%      3         6         3          26h
[root@k8s-master1 hpa]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
metrics-app-b96659c9c-5jxsg               1/1     Running   0          3m53s
metrics-app-b96659c9c-5lqpb               1/1     Running   0          5m24s
metrics-app-b96659c9c-6qx2p               1/1     Running   0          2m21s
metrics-app-b96659c9c-bqkbk               1/1     Running   0          3m53s
metrics-app-b96659c9c-f5vcf               1/1     Running   0          2m21s
metrics-app-b96659c9c-j24xn               1/1     Running   1          3h12m
metrics-app-b96659c9c-vpl4t               1/1     Running   0          3h12m
metrics-app-b96659c9c-wxp7z               1/1     Running   0          3m52s
metrics-app-b96659c9c-xztqz               1/1     Running   0          3m53s
metrics-app-b96659c9c-zhq5r               1/1     Running   0          5m24s
nfs-client-provisioner-6f54fc894d-dbvmk   1/1     Running   0          5h40m
nginx-969bfd4c9-g4zkc                     1/1     Running   0          25h
nginx-969bfd4c9-mn2rd                     1/1     Running   0          25h
nginx-969bfd4c9-rk752                     1/1     Running   0          25h

等待一會大概5分鐘就會進行副本的縮容
小結:

  1. 通過/metrics收集每個Pod的http_request_total指標;
  2. prometheus將收集到的信息彙總;
  3. APIServer定時從Prometheus查詢,獲取request_per_second的數據;
  4. HPA定期向APIServer查詢以判斷是否符合配置的autoscaler規則;
  5. 如果符合autoscaler規則,則修改Deployment的ReplicaSet副本數量進行伸縮。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章